在本篇文章中,我们将详细地讨论Sun公司的Java数据对象(JDO)标准。JDO允许我们使用Java对象,支持事务和多用户。与ODBC不同的是,它使我们无需考虑SQL和与数据库有关的其他东西。它与串行化也有所区别,因为它支持多个用户和事务。JDO允许Java开发人员将他们的数据模型用作数据模型,无需在“数据端”、“对象端”之间的转移方面花费大量的时间。
包括CocoBase、WebGainTOPLink和CastorJDO在内的多种产品都可以实现了JDO标准。既然有一种标准的方法,我们就可以只学习其中的一种,就象有了ODBC,我们就可以使用任何提供了驱动程序的数据库那样。
在本篇文章中,我们将使用Prism技术公司的OpenFusionJDO。读者在后面会发现,只有很小一部分代码使用了PrismTechAPI,其他部分都使用了标准的JDO标准。
创建Person对象
我们将首先创建一个Person对象,该对象遵循了JavaBean的惯例,可以对其属性执行get和set操作。需要注意的是,尽管我们是在创建这个类,但它并没有什么特别的,它没有继承或实现任何基本类。对一个可保持类的要求是:
1、所有域必须能够被JDO类访问(public或set*方法)
2、域的数据类型必须符合JDO规格。
3、不能支持一些类型的字段(例如Thread、File、Socket等不能串行化的字段)。
下面是符合上述要求的Person.java:
publicclassPerson{
privateStringname;
privateStringaddress;
privateStringssn;
privateStringemail;
privateStringhomePhone;
privateStringworkPhone;
//允许我们使用构造器创建Person对象
publicPerson(Stringname,Stringaddress,Stringssn,
Stringemail,StringhomePhone,StringworkPhone){
this.name=name;
this.address=address;
this.ssn=ssn;
this.email=email;
this.homePhone=homePhone;
this.workPhone=workPhone;
}
//方法
publicStringgetName(){returnname;}
publicStringgetAddress(){returnaddress;}
publicStringgetSsn(){returnssn;}
publicStringgetEmail(){returnemail;}
publicStringgetHomePhone(){returnhomePhone;}
publicStringgetWorkPhone(){returnworkPhone;}
publicvoidsetName(Stringname){this.name=name;}
publicvoidsetAddress(Stringaddress){
this.address=address;
}
publicvoidsetSsn(Stringssn){this.ssn=ssn;}
publicvoidsetEmail(Stringemail){this.email=email;}
publicvoidsetHomePhone(StringhomePhone){
this.homePhone=homePhone;
}
publicvoidsetWorkPhone(StringworkPhone){
this.workPhone=workPhone;
}
}
创建PersonPersist对象管理可保持性
现在已经有了Person对象,我们需要创建一些代码来管理这种可保持性。下面我们将详细讨论这些代码,并学习如何:
1、初始化JDO可保持性管理器。
2、向数据库中输入三个人的资料。
3、从数据库中显示人的资料。
4、修改其中一个人的名字。
5、从数据库中删除一个人的资料。
6、在main()方法中进行相关的处理。
第一步:初始化JDO可保持性管理器
我们从OpenFusion实现中导入了标准的JDO类和ManagedConnectionFactory,当然了我们也可以将它们抽象成一个独立的类。构造器使用javax.jdo.PersistenceManagerFactoryClass属性设置连接代理,这一点与在JDBC中设置数据库驱动程序的属性很相似。
packageaddressbook;
importjava.util.*;
importjavax.jdo.*;
import
com.prismt.j2ee.connector.jdbc.ManagedConnectionFactoryImpl;
publicclassPersonPersist
{
privatefinalstaticintSIZE=3;
privatePersistenceManagerFactorypmf=null;
privatePersistenceManagerpm=null;
privateTransactiontransaction=null;
//需要保持的人的数组
privatePerson[]people;
//现有对象标识符的向量
privateVectorid=newVector(SIZE);
publicPersonPersist(){
try{
Propertiesprops=newProperties();
props.setProperty("javax.jdo.PersistenceManagerFactoryClass",
"com.prismt.j2ee.jdo.PersistenceManagerFactoryImpl");
pmf=JDOHelper.getPersistenceManagerFactory(props);
pmf.setConnectionFactory(createConnectionFactory());
}catch(Exceptionex){
ex.printStackTrace();
System.exit(1);
}
}
连接代理是在名字为createConnectionFactory()的静态方法中创建的,该代理需要JDBCURL、JDBC驱动程序、用户名和口令。
publicstaticObjectcreateConnectionFactory(){
ManagedConnectionFactoryImplmcfi=new
ManagedConnectionFactoryImpl();
ObjectconnectionFactory=null;
try{
mcfi.setUserName("scott");
mcfi.setPassword("tiger");
mcfi.setConnectionURL(
"jdbc:oracle:thin:@localhost:1521:thedb");
mcfi.setDBDriver("oracle.jdbc.driver.OracleDriver");
connectionFactory=mcfi.createConnectionFactory();
}catch(Exceptione){
e.printStackTrace();
System.exit(1);
}
returnconnectionFactory;
}
第二步:在数据库中输入三个人的资料
PersistPeople()使用Person.java文件中的构造器创建了3个人的资料。。我们要作的第一件事是通过
getPersistenceManager()获得一个可保持性管理器,然后创建一个执行我们的任务的事务。为了保持这一对象结构图,我们简单地调用makePersistentAll(Object[])方法即可。代码底部的for()循环获得每个保持对象的唯一的ID,并保存起来供以后使用。
publicvoidpersistPeople(){
//创建人的资料的数组
people=newPerson[SIZE];
//创建3个人的资料
people[0]=newPerson("GarySegal","123FoobarLane",
"123-123-1234","[email protected]",
"(608)294-0192","(608)029-4059");
people[1]=newPerson("MichaelOwen",
"222BazzaLane,Liverpool,MN",
"111-222-3333","[email protected]",
"(720)111-2222","(303)222-3333");
people[2]=newPerson("RoyKeane",
"222TraffordAve,Manchester,MN",
"234-235-3830","[email protected]",
"(720)940-9049","(303)309-7599)");
//保持这3个人的资料
pm=pmf.getPersistenceManager();
transaction=pm.currentTransaction();
pm.makePersistentAll(people);
transaction.commit();
//获取被保持对象的对象ID
for(inti=0;i<people.length;i++){
id.add(pm.getObjectId(people[i]));
}
//关闭现有的保持性管理器,保证对象是从数据库而不是从保持性管理器的缓存中读取的
pm.close();
}
下面是一些可以针对保持性管理器的其他方法:
使实例成为可保持的:获得一个临时对象,并保持它。
删除可保持实例:从数据存储库中删除信息。
使实例临时化:使实例与可保持性管理器分离,而不删除在数据存储库中的信息。
使实例处于保持状态删除保持的实例使实例处于临时状态
makePersistent(Objecto)deletePersistent(Objecto)makeTransient(Objecto)
makePersistentAll(Object[]os)deletePersistentAll(Object[]os)makeTransientAll(Object[]os)
makePersistentAll(Collectionos)deletePersistentAll(Collectionos)makeTransientAll(Collectionos)
(这里是一个4X3的表格,可以参阅原稿中的英文表格)
第三步:显示数据库中人的信息
显示信息代码以获得可保持性管理器开始。我们使用上面代码中用persistPeople()方法保存的对象ID获得对象,调用对象的方法━━在本例中是gets,来得到我们输入的信息。我们可以发现,要保持我们的对象,并不需要编写大量的代码。
publicvoiddisplay(intend){
Personperson;
intmax=end<=SIZE?end:SIZE;
//获得一个新的可保持性管理器
pm=pmf.getPersistenceManager();
//从数据库中获取对象并进行显示
for(inti=0;i<max;i++){
person=(Person)pm.getObjectById(id.elementAt(i),
false);
System.out.println("Name:"+person.getName());
System.out.println("Address:"+
person.getAddress());
System.out.println("SSN:"+person.getSsn());
System.out.println("Email:"+person.getEmail());
System.out.println("HomePhone:"+
person.getHomePhone());
System.out.println("WorkPhone:"+
person.getWorkPhone());
}
pm.close();
}
第四步:改变其中一个人的名字
改变存储在数据库中的一个人的信息的代码也十分简单,它与显示数据库中人的信息的代码非常类似。在这里,我们需要创建一个事务(因为要修改其中的记录),使用定义的setName()方法修改一个人的名字,最终提交该事务,保存所作的修改。这种操作与处理临时对象之间真正的差别是,我们考虑是事务。
publicvoidchange(){
Personperson;
//从数据存储库中获取对象
pm=pmf.getPersistenceManager();
transaction=pm.currentTransaction();
//修改第二个保持记录的DataString字段
person=(Person)pm.getObjectById(id.elementAt(1),
false);
person.setName("SteveGerrard");
//提交事务并关闭可保持性管理器
transaction.commit();
pm.close();
}
第五步:删除一个人的资料
你自己能够想象出从数据库中删除第二个人资料的代码吗?因为我们已经了解了所有编写这一代码所需要的知识。仔细地研究一下下面的代码就会发现,我们使用了第二步中的可保持性管理器方法中提到的deletePersistent()方法。
publicvoiddelete(){
//从数据库中获取对象
pm=pmf.getPersistenceManager();
transaction=pm.currentTransaction();
//从数据库中删除第二个人的信息,并从ID向量中删除其ID
pm.deletePersistent(pm.getObjectById(id.remove(1),
false));
//提交事务并关闭可保持性管理器
transaction.commit();
pm.close();
}
第六步:在main()方法中运行上面的代码
最后,整个代码需要有一个main()串起来,在数据库中输入人的信息、改变其中一个人的名字,然后删除该人的资料。如果运行这一程序,就会看到程序运行到每一步时的地址簿。
publicstaticvoidmain(String[]args){
System.out.println("CreatePersonPersist");
PersonPersistpersonPersist=newPersonPersist();
System.out.println("Setupandpersistagroupofpeople");
personPersist.persistPeople();
System.out.println("Displaythepersistedpeople");
personPersist.display(SIZE);
System.out.println("Changeaname");
personPersist.change();
personPersist.display(SIZE);
System.out.println("Deleteaperson");
personPersist.delete();
personPersist.display(SIZE-1);
}
JDOEnhancer:创建JDOEnhancer的JDO描述符
现在,我们已经编写好了整个应用程序的源代码,下一步需要作的就是创建一个JDOEnhancer将要使用的
JDO描述符。读者一定会问,JDOEnhancer是什么?JDO架构是基于下面的理念的:一个JDO实现能够获取类的字节码,对它们进行处理,添加一些必要的功能。例如,JDOEnhancer将使类实现PersistanceCapable接口(因此我们不用自己编程实现这一接口),而且能够实现该接口中的一些方法。因此在对代码编译后我们就会发现,我们必须运行JDOEnhancer对字节码进行适当的处理。我们需要创建一个给出我们需要保持的类的信息的描述符文件,这一文件如下所示:
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEjdoSYSTEM
"file:/D:/Apps/OpenFusionJDO/xml/schema/jdo.dtd">
<jdo>
<packagename="addressbook">
<classname="Person"identity-type="datastore">
</class>
</package>
</jdo>
这只是一个最基本的文件,但能够满足我们的要求。当然了,还有许多更复杂的映射。下面是OpenFusion例子中一个稍微复杂一些的映射:
<classname="Department"identity-type="datastore">
<fieldname="name"/>
<fieldname="employees">
<collectionelement-
type="com.prismt.j2ee.jdo.examples.appKeyDepartment.Employee">
</collection>
</field>
<fieldname="manager"/>
</class>
</package>
</jdo>
现在我们已经编写好了代码和JDO描述符文件,我们将对它们进行整合,并讨论如何建立整个系统。要建立整个系统,我们只需要简单的几步工作即可:
1、编译代码。
2、运行JDOEnhancer。
3、使用JDOEnhancer的输出建立数据库。
4、运行应用程序。
第一步:编译代码
我想广大的读者想必已经知道如何运行javac了吧。在运行javac之前,我们只要保证正确地设置CLASSPATH就可以了。下面是一个在Windows平台上运行javac的例子:
%setOPENFUSION_DIR=D:\Apps\OpenFusionJDO
%set
CLASSPATH=%OPENFUSION_DIR%\lib\connector.jar;%OPENFUSION_DIR%\
lib\jndi.jar;%OPENFUSION_DIR%\lib\log4j.jar;%OPENFUSION_DIR%\l
ib\xerces.jar;%OPENFUSION_DIR%\lib\classes12.zip;%OPENFUSION_D
IR%\lib\jdo.jar;%OPENFUSION_DIR%\lib\jta-
spec1_0_1.jar;%OPENFUSION_DIR%\lib\ofjdo.jar;.
%javac?d.Person*.java
第二步:运行JDOEnhancer
JDOEnhancer需要使用在上一步编译中得到的字节码和我们先前建立的JDO描述符文件。下面是OpenFusionJDOEnhancer的完整语法:
javacom.prismt.j2ee.jdo.enhancer.JDOEnhancer
命令选项:
-cp开始搜索需要强化的类的基本路径,与CLASSPATH不同,它是编译后的可保持类所在的目录
-oc存储强化后的类的目录
-pdJDO描述符文件
可选项:
-db指定目标数据库[oracle、sybase等]
-od生成SQL脚本的目录
下面是为建立我们的应用程序而运行JDOEnhancer的一个例子:
%javacom.prismt.j2ee.jdo.enhancer.JDOEnhancer-oc.-pd
person.jdo-dboracle-oddb-cp.
第三步:使用JDOEnhancer的输出建立数据库
,只要使用?db和-od可选项,JDOEnhancer就能够创建建立数据库的数据库脚本。它能够创建许多脚本,但其中有一个的名字叫load_all.sql,打开该文件并将它加载到一个SQL提示符中。(例如sqlplusforOracle)
CREATESEQUENCEinstid_seqINCREMENTBY1
;
CREATETABLEJDO_addressbook_Person_SCO
(
inst_idINTEGERNOTNULL,
classINTEGERNOTNULL,
JDO_addressVARCHAR2(255),
JDO_emailVARCHAR2(255),
JDO_homePhoneVARCHAR2(255),
JDO_nameVARCHAR2(255),
JDO_ssnVARCHAR2(255),
JDO_workPhoneVARCHAR2(255)
)
;
CREATETABLEJDO_addressbook_Person
(
inst_idINTEGERNOTNULL,
classINTEGERNOTNULL,
JDO_addressVARCHAR2(255),
JDO_emailVARCHAR2(255),
JDO_homePhoneVARCHAR2(255),
JDO_nameVARCHAR2(255),
JDO_ssnVARCHAR2(255),
JDO_workPhoneVARCHAR2(255)
)
;
CREATETABLEprismjdoProp
(
nameVARCHAR2(255)PRIMARYKEY,
valueVARCHAR2(255)
)
;
CREATETABLEprismjdoExtents
(
class_idNUMBER(38,0)PRIMARYKEY,
class_nameVARCHAR2(255)UNIQUE,
app_keyVARCHAR2(255)
)
;
ALTERTABLEJDO_addressbook_Person_SCOADDPRIMARYKEY
(inst_id,class)
;
ALTERTABLEJDO_addressbook_PersonADDPRIMARYKEY(inst_id,
class)
;
INSERTINTOprismjdoExtentsVALUES(0,'addressbook.Person',
'com.prismt.j2ee.jdo.spi.DBKey')
;
COMMITWORK
;
INSERTINTOprismjdoPropVALUES('USE.RDBMS.TRIGGERS','true')
;
COMMITWORK
;
第四步:运行应用程序
现在已经建立了数据库,我们就可以运行应用程序了。怎么样,分享一下自己的劳动成果吧!
%javaaddressbook.PersonPersist
结束语
我们已经讨论了如何使用OpenFusionJDO实现来处理JDO标准。这是一个全新的领域,开发人员可以集中精力处理业务需求和对象,而无需对SQL十分精通。