持久化java技术对象到任何关系型数据库都是一项富有挑战性的任务,因为它必须潜心于序列化层次化结构的java对象到基于表结构的数据库,反之亦然。这个挑战是独一无二的,因为将java技术对象映射到数据库的列和记录的方式,必须要在速度和效率上同时达到最优化。java数据对象(jdo)规范,jsr-12,为使用标准的方式来透明地持久化简单java技术对象和访问数据库定义了api。使用jdo,java应用程序开发者可以在不使用任何数据库特定代码的情况下编写代码访问底层的数据存储。jdo被设计成在一个企业架构的多重层次中工作,包括java平台、标准版(java se,以前被称为j2se)、web层和应用服务器。
这篇文章提供了jdo的指南,它包含了jdo的基本要素,并且提供了使用jdo持久化java技术对象的示例代码。
引言
持久化,在程序退出后信息可以长期保存,在java语言中可以使用不同的选择完成。最简单的是文件i/o,但是这种方式不适合在企业级存储中使用(原因很明显)。其它的选择包括以下几种:
l 序列化(serialization):api简单,不支持查询、多用户共享、事务处理和局部数据读取或更新。另外,它不适合大容量数据存储。
l jdbc软件:具有完全访问的sql数据的功能。jdbc要求开发者必须显式地管理字段值以及把它们映射到关系数据库的表。在这种情况下,开发者必须熟悉另外一种开发语言(例如,查询语言sql)。
l ejb架构容器管理持久性(cmp):作为java企业级平台(java ee,以前被称为j2ee)组件模型的一部分,cmp为ejb容器提供了一种简便的对象持久化服务。然而,它不是一种对于java平台的普通持久化工具。
一种可行的选择是jdo api,它提供了一种标准的方式,使用java技术完成对象的持久化,通过结合xml元数据和增强的字节码简化了开发复杂性和降低开发成本。
jdo架构
高级的jdo api为开发者透明地存储数据提供了接口,开发者不必为每一种新的持久化数据存储而学习一种新的数据库访问语言(例如sql)。jdo也可以使用低级的api(例如jdbc)来存储数据。它使开发者可以编写java代码透明地访问底层的数据存储,而不需要使用数据库特定代码。jdo在jcp的项目中作为一个jsr开发:jdo1.0,从2002年开始存在,是jsr-12;jdo2.0,2005年初被核准并且正在开发中,是jsr-243。
jdo2.0是一个适合于简单java对象(pojos)持久化特点的jsr规范,很多厂家都在提供竞争性的实现。另外,很多厂家很可能在同一个的产品中实现jdo2.0和ejb3.0。这就允许你同时使用两种api,为你提供了逐渐迁移到ejb3.0 pojo的简单方法,将会变为持久化模型的选择。
jdo架构(如图1所示)的两个主要目的就是,为java应用程序开发者提供透明地以java技术为核心的访问持久化信息的方式,使数据存储的可插入式实现集成到应用服务器中。
图1 jdo架构
请注意,jdo没有定义数据存储的类型:你可以使用同样的代码持久化的你的java对象到关系型数据库、对象型数据库、xml和任何数据存储。
使用jdo的好处主要包括以下几点:
l 简便性(portability):使用jdo api编写的程序可以在不同开发商的多种可用的实现上运行,不用修改一行代码,甚至不用重新编译。
l 透明地访问数据库(transparent database access):应用程序开发者编写代码透明地访问底层数据存储,而不需要使用任何数据库特定代码。
l 易用性(ease of use):jdo api允许开发者只需要关注他们自己范围内的数据模型(domain object model,dom),而持久化的细节就留给jdo实现。
l 高性能(high performance):java应用程序开发者不需要担心数据访问的性能优化,因为这个任务已经委派给了jdo实现,它通过改善数据访问的模式以获得最佳性能。
l 和ejb集成(integration with ejb):应用程序可以利用ejb的特征,例如远程信息处理、自动分布式事务协调和贯穿整个企业级应用使用同样的doms实现安全性。
使用jdo,vs. ejb和jdbc
jdo并不意味着要取代jdbc。它们是两种以各自独一无二的能力互相补充的技术,具有不同技术背景和开发目的开发者可以使用二者中的一个。例如。jdbc通过直接的数据库访问控制和缓存管理,提供给开发者更大的弹性,。jdbc是一种在工业界被广泛认可的成熟技术。另一方面,jdo,通过隐藏sql提供给开发者更大的简便性。它将java平台开发者从必须熟悉或学习sql中解脱出来,而将精力集中在dom上,同时jdo管理在持久存储中对象存储的字段到字段的细节。
jdo被设计成ejb的补充。cmp为容器提供简便的持久化,而jdo可以以两种方式集成到ejb中:(1)通过会话bean,它含有jdo persistence-capable类(会话bean的持久化助手类)用来实现依赖对象;(2)通过实体bean,它含有被用作bmp和cmp代理的jdo persistence-capable类。
你可以学习更多关于jdo和jdbc之间的关系,还有ejb2.0 cmp和jdo之间的关系。
pojo之路
jdo和ejb之间在持久化模型上显著的差别曾经在开发者中间引起了混乱。作为回应,sun微系统正领导一个社区项目为java技术社区创建pojo持久化模型。这个项目在jsr-220的赞助下执行,由linda demichiel领导。jdo2.0(jsr-243)的专家组成员被邀请加入到ejb3.0(jsr-220)专家组中。
创建pojo持久化模型的目的是为所有使用java se和java ee平台的java应用程序开发者提供一个对象―关系(object-relational)映射工具。值得注意的是oracle正以co-specification lead的身份加入到sun ejb3.0。ejb3.0的公众评论草案已经可以得到。
jsr-243(jdo2.0)遵循了那些来自于jsrs220和243规范的领导写给java技术社区的信件所描述的轮廓。
jdo2.0并不打算作为ejb3.0持久化特定api的集中,而是作为jdo
要了解更多关于持久化模型的知识,请查看ejb/jdo持久化faq。
jdo class类型
在jdo中一共有三种类型的类:
l persistence-capable:这种类型代表那些实例可以被持久化到一个数据存储中的类。请注意,这些类在jdo环境中被使用之前,需要通过jdo元数据规范进行加强。
l persistence-aware:这些类操纵persistence-capable类。jdohelper类包含了一些方法,它们允许询问一个persistence-capable类的实例的持久化状态。请注意,这些类使用最小化的jdo元数据加强。
l normal:这些不可被持久化,并且对持久化一无所知。另外它们不需要jdo元数据。
jdo实例的生命周期
jdo管理一个对象从创建到删除的生命周期。在它的生命周期,jdo实例不断地转换它的状态,直到最后被java虚拟机(jvm)作为垃圾回收。状态的转换使用persistencemanager类的方法完成,包括transactionmanager――例如makepersistent()、maketransient()、deletepersistent()――和提交或者回滚更改。
表1显示jdo规范定义的10种状态。前面的七种是必须的,后面的三种是可选的。如果一个实现不支持某些操作,那么就不会获得三种可选的状态。
表1 jdo生命周期
状态 | 描述 |
transient | 任何使用开发者定义的构造函数创建的对象,都不包括持久化环境。一个瞬时实例没有jdo身份。 |
persistent-new | 被应用程序组件请求的任何对象都变为持久的,通过使用persistencemanager类的makepersistent()。这样的一个对象将会拥有一个分配的jdo身份。 |
persistent-dirty | 在当前事务中被改变的持久对象。 |
hollow | 代表在数据存储中特定数据的持久对象,但是在它的实例中没有包含值。 |
persistent-clean | 代表在数据存储中的特定事务数据的持久对象,并且它们的数据在当前事务处理中还没有被改变。 |
persistent-deleted | 代表在数据存储中的特定数据的持久对象,并且在当前事务处理中已经被删除。 |
persistent-new-deleted | 在同一个事务处理中最近被持久化和删除的持久对象。 |
persistent-nontransactional | 代表数据存储中的数据的持久对象,当前它们的值已经被装载,但是还没有事务处理一致。 |
transient-client | 代表一个瞬时事务处理实例的持久对象,它们的数据在当前事务中还没有被改变。 |
transient-dirty | 代表一个瞬时事务处理实例的持久对象,它们的数据在当前事务中已经被改变。 |
图2显示了jdo实例各状态之间的转换。
图2 jdo实例的状态转换
本文稍后的代码片断,将示范如何执行我们刚刚讨论的操作。
jdo参考实现
jdo参考实现,来自于sun微系统,已经可用,一同发行的还有一种被称为fstore的基于文件的存储机制。sun已经把jdo捐献给开源社区。jdo1.0和jdo2.0将会作为apache jdo项目的一部分进行开发。但是由于时间的限制,jdo2.0的参考实现并不是作为apache项目建立的,而是作为一个jpox 发行。一些商业实现也是可用的。
jdo编程模型
jdo定义了两种类型的接口:jdo api(在javax.jdo包中)和jdo服务提供者接口(spi)(在javax.jdo.spi包中)。jdo api面向应用程序开发者,而jdo spi面向容器提供者,和jdo卖主。
一个应用程序包含两个主要的接口:
l persistencemanagerfactory代表了应用程序开发者用来获得persistencemanager实例的访问点。这个接口的实例可以被配置和序列化以备后来使用。然而,需要注意的是,一旦第一个persistencemanager实例从persistencemanagerfactory中被获得,这个工厂就不再是可配置。你可以使用下面的代码来获得persistencemanagerfactory。
// 为jdo实现和数据存储设置一些属性
properties props = new properties();
props.put(...);
// 得到一个persistencemanagerfactory
persistencemanagerfactory pmf = jdohelper.getpersistencemanagerfactory (props);
l persistencemanager是jdo-aware应用部分的主要接口。它提供了方法来持久化一个对象,也可以重新得到持久对象和将它们从持久存储中移除。可以使用下面的方法获得persistencemanager。
persistencemanager pm = pmf.getpersistencemanager ();
一旦获得了persistencemanager对象后,应用程序就可以一些任务,例如:持久化一个对象、从持久数据中获得一个对象、从持久数据中删除一个对象、更新一个对象等等。
接下来的代码片断示范了如何持久化一个对象,它更新一个对象的状态从transient到hollow。
employee emp = new employee("sarah jones", 23, 37000.00);transaction tx;
try {tx = pm.currenttransaction();
tx.begin();
pm.makepersistent(emp);
tx.commit();
} catch (exception e) { if(tx.isactive()) {tx.rollback();
}
}
从持久数据中获得一个对象同样简单,你可以使用extent(一个信息的持有者)或者query(提供了更精确的过滤)。下面是一个使用extent的例子:
try {tx = pm.currenttransaction();
tx.begin();
extend ex = pm.getextent(employee.class, true);
iterator i = ex.iterator();
while(i.hasnext()) {employee obj = (employee) i.next();
}
tx.commit();
} catch (exception e) { if(tx.isactive()) {tx.rollback();
}
}
最后,从持久数据中删除一个对象也可以简单完成,首先获得一个从持久数据中获得一个对象,然后调用deletepersistent(obj)方法。
查询对象
jdo规范要求开发商必须提供使用jdoql的查询能力,jdoql是一种面向围绕被持久化对象的查询语言。persistencemanager类定义了构造query实现类的实例的方法。一个查询过滤器可以被指定为一个布尔表达式,就像sql的布尔操作符。
生命周期开发:在你的应用程序中使用jdo
可以通过以下六个步骤建立一个jdo应用:
1. 设计你的范围内的将会正常使用的类。对一个要求持久化的类的唯一要求就是它要有一个默认构造函数,访问权限可能是private。
2. 使用元数据定义持久化定义:在这个步骤中,你编写元数据,指定那些类和字段应该被持久化等等。这个文件可以包含对于一个类或一个或者多个包含持久类的包的持久化信息。一个类的元数据文件的名称是这个类的名字加上“.jdo”后缀,注意,这个文件必须放在和.class文件相同的目录中。对于整个包的元数据文件的必须包含在一个称作package.jdo的文件中。元数据文件可以使用xdoclet或手动开发。下面是一个简单的对于两个类的元数据文件:
3. 编译这些类,并且使用jdo加强器来加强它们。任何persistence-capable类的实例在被jdo持久化引擎管理之前必须被加强。jdo字节码加强器通过对类定义特定的改变来装换这个类,使得任何持久实例可以和数据存储中的数据描述保持同步。和参考实现一起发行的jdo加强器,能够从sun微系统得到,可以使用如下的方式运行:
prompt> java -classpath
%jdo-home%/lib/jdo.jar;%jdo-home%/lib/jdori.jar;
%jdo-home%/jdori-enhancer.jar com.sun.jdori.enhancer.main -d
/enhanced -s . -f path/tp/package.jdo path/to/theclasses.class
注意:对jdo加强器最重要的参数是一个.jdo文件的名字和.class文件的名字。另外,
l -d选项指定输出文件的目标文件夹;
l -s选项指定jdo和class文件的源文件夹;
l -f选项强制重写输出文件。
如果忽略这个步骤,那么当你运行应用程序和持久化一个对象时将会抛出classnotpersistencecapableexception异常。
4. 为被持久化的类建立数据库表。如果你已经有了一个数据库方案,那么这一步是可选的。基本上,你必须建立表、索引和在jdo元数据文件中为类定义的外键。有些jdo实现包含一个方案工具,可以根据jdo元数据文件产生所有的这些东西。
5. 编写代码来持久化你的对象。在这个步骤中,你要指定那些类在什么时间被实际持久化。正如前面提到的,最初的步骤是获得一个persistencemanager的使用权。
6. 运行你的应用程序。使用java命令,并且包含必要的.jar文件在你的classpath中。
结束
jdo提供了基于接口的数据存储定义和事务处理,以及持久存储的数据到本地java技术对象的转换和选择。它致力于三种情况的需求:(1)一种持久保存java技术对象到事务性数据存储的标准。(2)一种对待关系性数据库数据像java技术对象一样的标准方式。(3)一种联合那些对象定义事务性语义的标准方式。
jdo api,仅仅是由一些接口组成,非常便于学习和使用,但是更重要的是它为对象持久化定义了一种标准。今后将会有很多jdo实现供选择,其中有些将是免费的。jdo允许你通过使用pojo来获得它的简便性,并非使用私有的api。
jdo有一个充满活力的社区。所以如果你正在为你的pojo寻找持久化解决方案,jdo是一个通过jcp项目开发的标准。jdo为pojo持久化提供了一个丰富和具有全部特征的jsr规范,并且很多开发商正在提供竞争性的jdo实现。ejb3.0,正由sun微系统和来自于不同的持久化开发商的专家创建,将是未来持久化模型的选择。
查看原文。
闽公网安备 35060202000074号