Google App Engine for Java 第 3 部分持久性和关系Word下载.docx
《Google App Engine for Java 第 3 部分持久性和关系Word下载.docx》由会员分享,可在线阅读,更多相关《Google App Engine for Java 第 3 部分持久性和关系Word下载.docx(13页珍藏版)》请在冰豆网上搜索。
与原始的GoogleAppEngine一样,AppEngineforJava依靠Google的内部基础设施,实现可伸缩的应用程序开发的BigThree:
分布、复制和负载均衡。
由于使用的是Google基础设施,因此所有神奇的地方大都发生在后台,可以通过AppEngineforJava的基于标准的API获得。
数据存储接口是以JDO和JPA为基础的,而它们自身又是以开源的DataNucleus项目为基础。
AppEngineforJava还提供了一个低级别的适配器API,用来直接处理基于Google的BigTable实现的AppEngineforJava数据存储(要了解更多有关BigTable的信息,请参见第1部分)。
然而,AppEngineforJava数据持久性并不像纯GoogleAppEngine中的持久性那样简单。
由于BigTable不是一个关系数据库,JDO和JPA的接口出现了一些抽象泄漏。
例如,在AppEngineforJava中,您无法进行那些执行连接的查询。
您可以在JPA和JDO间设置关系,但它们只能用来持久化关系。
并且在持久化对象时,如果它们在相同的实体群中,那么它们只能被持久化到相同的原子事务中。
根据惯例,具有所有权的关系位于与父类相同的实体群中。
相反,不具有所有权的关系可以在不同的实体群中。
重新考虑数据规范化
要使用AppEngine的可伸缩的数据存储,需要重新考虑有关规范化数据的优点的教导。
当然,如果您在真实的环境中工作了足够长的时间,那么,您可能已经为了追求性能而牺牲过规范化了。
区别在于,在处理AppEngine数据存储时,您必须尽早且经常进行反规范化。
反规范化不再是一个忌讳的字眼,相反,它是一个设计工具,您可以把它应用在AppEngineforJava应用程序的许多方面。
当您尝试把为RDBMS编写的应用程序移植到AppEngineforJava时,AppEngineforJava的持久性泄漏的主要缺陷就会显露出来。
AppEngineforJava数据存储并不是关系数据库的临时替代物,因此,要把您对AppEngineforJava所做的工作移植到RDBMS端口并不容易。
采用现有的模式并把它移植到数据存储中,这种场景则更为少见。
如果您决定把一个遗留的Java企业应用程序移植到App引擎中,建议您要小心谨慎,并进行备份分析。
GoogleAppEngine是一个针对专门为它设计的应用程序的平台。
GoogleAppEngineforJava支持JDO和JPA,这使得这些应用程序能够被移植回更传统的、未进行规范化的企业应用程序。
关系的问题
AppEngineforJava目前的预览版的另外一个缺点是它对关系的处理。
为了创建关系,现在您必须对JDO使用AppEngineforJava特有的扩展。
假设键是在BigTable的工件的基础上生成—也就是说,“主键”将父对象键编码到其所有子键中—您将不得不在一个非关系数据库中管理数据。
另外一个限制是持久化数据。
如果您使用非标准的AppEngineforJavaKey类,事情将会变得复杂。
首先,把模型移植到RDBMS时,如何使用非标准Key?
其次,由于无法使用GWT引擎转换Key类,因此,任何使用这个类的模型对象都无法被作为GWT应用程序的一部分进行使用。
当然,撰写这篇文章时,GoogleAppEngineforJava还是纯粹的预览模式,没有到发布的最佳时间。
学习JDO中的关系文档(很少,而且包含一些不完整的示例)时,这点就变得显而易见了。
AppEngineforJava开发包提供了一系列的示例程序。
许多示例都使用JDO,没有一个使用JPA。
这些示例中没有一个示例(包括一个名为jdoexamples的示例)演示了关系,即使是简单的关系。
相反,所有的示例都只使用一个对象把数据保存到数据存储中。
GoogleAppEngineforJava讨论组充斥着有关如何使简单关系起作用的问题,但却鲜有答案。
很显然,有些开发人员有办法使其起作用,但是实现起来都很困难,而且遇到了一些复杂情况。
AppEngineforJava中的关系的底线是,无需从JDO或JPA获得大量支持就能够管理它们。
Google的BigTable是一种已经经过检验的技术,可用来生成可伸缩的应用程序,然而,您还可以在此基础上进行构建。
在BigTable上进行构建,您就不必处理还不完善的API层面。
另一方面,您只要处理一个较低级别的API。
AppEngineforJava中的JavaDataObjects
把传统的Java应用程序移植到AppEngineforJava中,甚至是给出关系挑战,这些可能都没有什么意义,然而,持久性场景还是存在的,这时使用这个平台就有意义了。
我将使用一个可行的示例来结束本文,您将体验AppEngineforJava持久性是如何工作的。
我们将以第2部分中建立的联系人管理应用程序为基础,介绍如何添加支持,以使用AppEngineforJava数据存储工具持久化Contact对象。
在前面的文章中,您创建了一个简单的GWTGUI,对Contact对象进行CRUD操作。
您定义了简单的接口,如清单1所示:
清单1.简单的ContactDAO接口
packagegaej.example.contact.server;
importjava.util.List;
importgaej.example.contact.client.Contact;
publicinterfaceContactDAO{
voidaddContact(Contactcontact);
voidremoveContact(Contactcontact);
voidupdateContact(Contactcontact);
List<
Contact>
listContacts();
}
接下来,创建一个模拟版本,与内存集合中的数据进行交互,如清单2所示:
清单2.模拟DAO的ContactDAOMock
importjava.util.ArrayList;
importjava.util.Collections;
importjava.util.LinkedHashMap;
importjava.util.Map;
publicclassContactDAOMockimplementsContactDAO{
Map<
String,Contact>
map=newLinkedHashMap<
();
{
map.put("
rhightower@"
newContact("
RickHightower"
"
"
520-555-1212"
));
scott@"
ScottFauerbach"
520-555-1213"
bob@"
BobDean"
520-555-1214"
}
publicvoidaddContact(Contactcontact){
Stringemail=contact.getEmail();
map.put(email,contact);
publicList<
listContacts(){
returnCollections.unmodifiableList(newArrayList<
(map.values()));
publicvoidremoveContact(Contactcontact){
map.remove(contact.getEmail());
publicvoidupdateContact(Contactcontact){
map.put(contact.getEmail(),contact);
现在,使用与GoogleAppEngine数据存储交互的应用程序替换模拟实现,看看会发生什么。
在这个示例中,您将使用JDO持久化Contact类。
使用GoogleEclipsePlugin编写的应用程序已经拥有了使用JDO所需的所有库。
它还包含了一个jdoconfig.xml文件,因此,一旦对Contact类进行了注释,您就已经准备好开始使用JDO。
清单3显示扩展后的ContactDAO接口,可使用JDOAPI进行持久化、查询、更新和删除对象:
清单3.使用JDO的ContactDAO
importjavax.jdo.JDOHelper;
importjavax.jdo.PersistenceManager;
importjavax.jdo.PersistenceManagerFactory;
publicclassContactJdoDAOimplementsContactDAO{
privatestaticfinalPersistenceManagerFactorypmfInstance=JDOHelper
.getPersistenceManagerFactory("
transactions-optional"
);
publicstaticPersistenceManagerFactorygetPersistenceManagerFactory(){
returnpmfInstance;
PersistenceManagerpm=getPersistenceManagerFactory()
.getPersistenceManager();
try{
pm.makePersistent(contact);
}finally{
pm.close();
}
@SuppressWarnings("
unchecked"
)
Stringquery="
selectfrom"
+Contact.class.getName();
return(List<
)pm.newQuery(query).execute();
pm.currentTransaction().begin();
//Wedon'
thaveareferencetotheselectedProduct.
//Sowehavetolookitupfirst,
contact=pm.getObjectById(Contact.class,contact.getId());
pm.deletePersistent(contact);
pm.currentTransaction().commit();
}catch(Exceptionex){
pm.currentTransaction().rollback();
thrownewRuntimeException(ex);
publicvoidupdateContact(Contactcontact){
Stringname=contact.getName();
Stringphone=contact.getPhone();
contact.setName(name);
contact.setPhone(phone);
contact.setEmail(email);
逐一比对方法
现在,考虑一下使用清单3中的每个方法时发生的情况。
您将会发现,方法的名字可能是新的,但它们的动作大部分情况下都应该感到熟悉。
首先,为了获取PersistenceManager,创建了一个静态的PersistenceManagerFactory。
如果您以前使用过JPA,PersistenceManager与JPA中的EntityManager很相似。
如果您使用过Hibernate,PersistenceManager与HibernateSession很相似。
基本上,PersistenceManager是JDO持久性系统的主接口。
它代表了与数据库的会话。
getPersistenceManagerFactory()方法返回静态初始化的PersistenceManagerFactory,如清单4所示:
清单4.getPersistenceManagerFactory()返回PersistenceManagerFactory
privatestaticfinalPersistenceManagerFactorypmfInstance=JDOHelper
.getPersistenceManagerFactory("
publicstaticPersistenceManagerFactorygetPersistenceManagerFactory(){
returnpmfInstance;
addContact()方法把新的联系人添加到数据存储中。
为了做到这点,需要创建一个PersistenceManager实例,然后,调用PersistenceManager的makePersistence()方法。
makePersistence()方法采用临时的Contact对象(用户将在GWTGUI中填充),并且使其成为一个持久的对象。
所有这些如清单5所示:
清单5.addContact()
publicvoidaddContact(Contactcontact){
PersistenceManagerpm=getPersistenceManagerFactory()
.getPersistenceManager();
try{
pm.makePersistent(contact);
}finally{
pm.close();
注意在清单5中,persistenceManager是如何被封入在finally块中。
这确保能够把与persistenceManager关联的资源清除干净。
如清单6所示,listContact()方法从它所查找的persistenceManager中创建一个查询对象。
它调用了execute()方法,从数据存储中返回Contact列表。
清单6.listContact()
@SuppressWarnings("
publicList<
Stringquery="
return(List<
在从数据存储中删除联系人之前,removeContact()通过ID查找联系人,如清单7所示。
它必须这么做,而不仅仅是把联系人直接删除,这是因为来自GWTGUI的Contact对JDO一无所知。
在删除前,您必须获得与PersistenceManager缓存关联的Contact。
清单7.removeContact()
publicvoidremoveContact(Contactcontact){
pm.currentTransaction().begin();
//Wedon'
//Sowehavetolookitupfirst,
contact=pm.getObjectById(Contact.class,contact.getId());
pm.deletePersistent(contact);
pm.currentTransaction().commit();
}catch(Exceptionex){
pm.currentTransaction().rollback();
thrownewRuntimeException(ex);
清单8中的updateContact()方法与removeContact()方法类似,用来查找Contact。
然后,updateCon