在企业级的应用开发中,常需要有良好的持久化技术来支持数据存储。通过良好的规范或API,将企业的领域业务对象进行持久化存储,大多采用O/R映射技术来进行模式化的数据转换及自动映射工作。
JDO(Java Data Object)是JCP中较早开发出来并形成规范的JSR12,该规范对数据的持久化存储进行了一系列规范,并已有众多的商业产品和开源项目是基于该规范。作为一种需要引起重视的技术,研究并探讨其企业应用可行性是十分重要的。
以下主要对JDO(JDO 1.0规范)的应用开发技术作扼要介绍,通过该文,可以由浅入深、并较为全面地了解JDO,掌握主要的技术细节及过程,理解其运行机制,并对企业级应用有个总体的把握,这将有助于企业应用软件的技术选型、体系架构及分析设计活动。
该文适合企业应用架构师、及关心数据持久层设计开发人员。
JDO基本思想及特点
企业信息系统的一个重要问题是解决数据的存储,即持久化。在软件开发过程中,分析员分析领域业务,提取出领域业务模型,并对应设计出数据库中需要进行存储业务数据的数据库表及相应字段。
并根据业务流程,设计业务处理逻辑单元,进行数据的加工、处理及存储、查询等业务。其中一个较为繁烦、枯燥的工作,就是处理大量的数据持久化代码。为了解决数据从业务对象层向数据存储层之间的转换工作,JDO提供了相应的开发规范及API,解决了由Java对象直接存储为数据库相应表的底层处理过程,有助于设计人员更加专注于面向业务流程、面向业务对象等较高层次的应用。
由于采用JDO的映射机制,能降低了业务系统与数据存储系统的耦合,使得业务系统相对于关系数据库或对象型数据库,具有可移植性,同时,由于采用面向对象(而非传统的面向记录)的持久化技术,系统更为轻便、简洁,增强了可维护性。
JDO应用示例及分析
以下将通过一些示例,由浅及深地讲解JDO技术。
临时对象与持久对象
这是一个普通的业务对象的代码。
package business.model;
public class Book {
private String isbn;
private String name;
private Date publishDate;
public void setISBN(String isbn){
this.isbn = isbn;
}
public String getISBN(){
return this.isbn;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setPublishDate(Date pubDate){
this.publishDate = pubDate;
}
public Date getPublishDate(){
return this.publishDate;
}
}
现在将它作为一个JDO中对象保存到数据库中。代码如下:
Book book = new Book();
book.setISBN(“isbn-1234567”);
book.setName(“Java设计模式”);
PersistenceManager manager = persistenceManagerFactory.getPersistenceManager();
manager.currentTransaction().begin();
manager.makePersistence(book);
manager.currentTransaction().commit();
Book类的实例book对JDO的API而言,就是一个持久对象。类Book是可持久类。那任何一个普通java类都是JDO的可持久类吗?不是的。只有具备以下的条件,一个对象才可以被JDO持久到数据库中。
它所属类应标记为可持久的类,有以下两种方法:
显式:实现接口,javax.jdo.PersistenceCapable即可;
隐式:以Sun的JDO参考实现为例,Book.java类的相同路径下还须有Book.jdo文件。
< ?xml version=“1.0” encoding = “UTF-8”?>
< !DOCTYPE jdo SYSTEM “jdo.dtd”>
< jdo>
< package name = “business.model”>
< class name = “Book”/>
< /package>
< /jdo>
并通过字节码增强工具(本例采用Sun的字节码增强工具)处理,
javac Book.java
java com.sun.jdori.enhancer.Main Book.class Book.jdo。
通过上述两种方法,获得的Book.class才是一个可持久的类。
字节码增强的有如下功能:当应用程序通过set方法修改某个字段1时,由于通过增强过程,在其内部插入了某些代码,JDO会获得数据状态变化的信息,从而在持久过程中,进行有选择性的处理。
按照JDO规范,增强后的类可以在不同的JDO实现上使用,而无需重新编译或增强。
并不是所有Book对象都是持久对象,只有当makePersistence后,该对象才是持久对象,并会通过JDO实现存储到数据库中。通过JDO的供应商扩展标记符(vendor-extension),可详细描述Book类的存储特性,如为该可持久类指定数据库表和对应字段。
持久对象查询 JDO查询主要有以下两种方式。 使用Extend查询 Extend可以查询指定类及子类的持久对象。 PersistenceManager manager = persistenceManagerFactory.getPersistenceManager(); manager.currentTransaction().begin(); Extend extend = manager.getExtend(Book.class,true);//true表明同时查询子类 Iterator it = extend.iterator(); while(it.hasNext()){ Book book = (Book)it.next(); System.out.println(book.getISBN()); } extend.closeAll(); manager.currentTransaction().commit(); Extend查询方法,提供了一种基于类的查询途径,它可以与下面的Query构成更为强大的查询。 使用Query查询 Query可以指定过滤条件,是一种常用的查询方式。 下例是查找条件为“书名以‘Java设计模式’开头且出版日期小于今天”的书籍。 String filter = “((String)name).startsWith(\”Java设计模式\”) && publishDate < today”; Query query = pm.getQuery(Book.class,filter); query.declareImports(“import java.util.Date”); query.declareParameters(“Date today); Date today = new Date(); results = (Collection)query.execute(today);//传入参数值today if (results.isEmpty()){ System.out.println(“No data!”); }else{ Iterator it = results.iterator(); while(it.hasNext()){ Book book = (Book)it.next(); System.out.println(“Book Name:” + book.getName() + “, ISBN:” + book.getISBN()); } } 注:该条件使用了一个变元‘today’,通过“declareParameters”来声明该变量,并在“execute”方法中传入该变量的实例。 这种带参数的查询,很类似于我们以前采用JDBC的带?的查询方式。 其中startsWith(String s)是JDO提供的标准字符方法,类似的方法还有endsWith(String s)。 JDOQL:上述使用的就是一个JDOQL样例,JDOQL是JDO规范一个组成部分。使用JDOQL可以使用应用在不同的JDO实现上运行。为了解决JDOQL的某些不足,JDO规范提供了支持特定JDO供应商查询语句接口。 查询排序 下例是将查询结果按“出版日期降序、书名升序”进行排序。 Query query = pm.newQuery(Book.class, filter); String orderStr = “publishDate decending, name ascending”; query.setOrdering(orderStr); results = query.execute(today);
对象更新
当客户端对业务数据进行了更新后,需要通过业务过程将其更新到持久层中。
这有两个过程,首先根据主键找到该实例,接着更新字段及提交。
如下例,将指定书目编号的书本的出版日期进行更改。
public void updateBookPublishDate(String isbn, Date newDate){
PersistenceManager pm = null;
try{
pm = pmf.getPersistenceManager();
Object obj = pm.newObjectIdInstance(Book.class,isbn);
Book book = (Book)pm.getObjectById(obj,true);
book.setPublishDate(newDate);
}catch(Exception e){
xxxContext.setRollbackOnly();
throw new Exception(e);
}finally{
try{
if (pm != null && !pm.isClosed()){
pm.close();
}
}catch(Exception ex){
System.out.println(ex);
}
}
注,在PersistenceManager使用newObjectIdInstance()方法时,JDO是如何知道通过书目编号ISBN来找到该对象呢?
其实在本可持久类Book的jdo描述文件中,还需提供如下信息:
< ?xml version=“1.0” encoding = “UTF-8”?>
< !DOCTYPE jdo SYSTEM “jdo.dtd”>
< jdo>
< package name = “business.model”>
< class name = “Book” identity-type=“application” objectid-class=“BookKey” >
< field name=“isbn” primary-key=“true”/>
< /class>
< /package>
< /jdo>
其中“identity-type=“application””声明可持久类Book采用程序标识方式,即应用程序传入ID(字段isbn为“primary-key”)信息,JDO实现构造出指定的“objectid-class”的实例(即newObjectIdInstance过程),并由JDO来检索出指定的持久化对象(即getObjectById)。
BookKey类源码如下:
package businesss.model;
public class BookKey implements java.io.Serializable{
public String isbn;
public BookKey(){
}
public BookKey(String oid){
isbn = oid;
}
public String toString(){
return isbn;
}
public Boolean equals(Object obj){
return isbn.equals((BookKey)obj).isbn);
}
public int hashCode(){
return isbn.hashCode();
}
}
符合 JDO 的“objectid-class”类,如“BookKey”,须具备以下条件:
类声明为 public,并实现 java.io.Serializable;
带有一个公有且不带参数的构造方法;
当字段作为主键时,须有公有的,且名称和类型与持久类的字段一致,如:public String isbn;
equals 和 hashCode 须使用全部(特指多字段的联合主键)的主键字段值;
类必须有一个构造方法,与 toString 方法的处理过程是逆向过程;即将 toString 的输出值,作为该构造方法的输入值,又可以重新生成该实例(如构造方法“public BookKey(String oid)”)。
综上所述,如果Book由两个字段作为主键,如isbn和name,则可能的代码是pm.newObjectIdInstance(Book.class,isbn+“#”+name),且BookKey的构造方法作相应更改,并有两个公有字段“isbn”和“name”。
对象删除
对象删除采用方法deletePersistence。示例如下:
pm.currentTransaction().begin();
Object obj = pm.newObjectIdInstance(Book.class,isbn);
Book book = (Book)pm.getObjectById(obj,true);
pm.deletePersistence(book);
pm.currentTransaction().commit();
获得PersistenceManager实例
上述的所有操作与需要PersistenceManager实例,它可以在两种环境方法下获得:非受管环境和受管环境。
非受管环境
非受管环境是多指两层开发模式,应用程序直接获得资源对象,进行业务操作。一般事务管理、安全管理或资源管理都需要应用程序自行维护。
Properties properties = new Properties();
properties.put(“javax.jdo.PersistenceManagerFactoryClass”, “com.xxx.jdo.xxxPMFClass”);
properties.put(“javax.jdo.option.ConnectionURL”, “xxx”);
properties.put(“javax.jdo.option.ConnectionUserName”, “xxx”);
properties.put(“javax.jdo.option.ConnectionPassword”, “xxx”);
PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(properties);
PersistenceManager pm = pmf.getPersistenceManager();
与JDBC获取类似。
受管环境
受管环境一般是多层开发模式,尤其是处于J2EE应用环境中,程序通过容器获得资源对象,进行业务操作,由于在容器环境下,事务、安全及资源管理都由容器进行统一集中管理,从而简化了代码结构。
以下是EJB(EntityBean、SessionBean、MessageDrivenBean)中的setXXXContext中的代码示例。
private PersistenceManagerFactory pmf;
public void setXXXContext(XXXContext context){
try{
InitialContext ctx = new InitialContext();
Object obj = ctx.lookup(“java:compenvjdofactory”);
pmf = (PersistenceManagerFactory)PortableRemoteObject.narrow(o,PersistenceManagerFactory.class);
}catch(NamingException e){
throw new Exception(e);
}
}
PMF是如何绑定到J2EE环境下的JNDI上,有兴趣可参考JCA相关的技术文档。
事务管理
事务管理及使用,主要有以下三种情形。
使用JDO事务的Bean管理情形
一般在非J2EE环境下,使用该事务管理模式。
PersistenceManager pm = pmf.getPersistenceManager();
pm.currentTransaction().begin();
//do some business with jdo
pm.currentTransaction().commit();
pm.close();
使用JTA事务的Bean管理情形
一般在J2EE环境下,采用Bean管理的事务情形下,使用以下方式。
该方式可用在EJB的事务环境下。
xxxContext.getUserTransaction().begin();
PersistenceManager pm = pmf.getPersistenceManager();
//do some business with jdo
xxxContext.getUserTransaction().commit();
pm.close();
使用JTA事务的容器管理情形
一般在J2EE环境下,采用容器管理的事务情形下,使用如下方式。
如下是某个会话Bean的业务方法。
public void doBusiness(){
PersistenceManager pm ;
try{
pm = pmf.getPersistenceManager();
//do some business with jdo
}catch(Exception e){
xxxContext.setRollbackOnly();
System.out.println(e);
}finally{
try{
if (pm != null && !pm.isClosed())
pm.close();
}catch(Exception ex){
System.out.println(ex);
}
}
}
综上,可以得出结论,JDO的操作完全与JDBC的操作相差无几。
JDO高级应用
复杂对象的持久化
在实际的应用中,一个可持久化类要远比Book类复杂很多。它可能会引用其它的Java类型、类、集合或数组,及可能复杂的继承关系。
当这些对象的状态发生变化时,JDO是如何感知及跟踪状态变化?
JDO提供了相应的API及规范来实现该功能。
基本类型及引用
可持久化类的字段能被JDO实现进行持久化的原则。
原始类型、java.util.Date等被支持(其它较为复杂或可选特性,详见JDO规范);
如果引用是一个可持久类,则JDO进行持久化处理;
通过元数据(如jdo文件)声明的字段,一般是非可持久化类的引用,JDO进行持久化;
前面两种情形,当状态发生变化时,JDO会自动感知,但如果引用是非可持久化类,则需要代码进行显式通知,否则JDO不会将变化进行存储。如下例:
public class Book {
……
private Object picture;
public void setPicture(Object pic){
picture = pic;
}
public Object getPicture(){
Return picture;
}
}
该类字段picture需要持久化,但java.lang.Object不是一个可持久类,故声明如下:
< ?xml version=“1.0” encoding = “UTF-8”?>
< !DOCTYPE jdo SYSTEM “jdo.dtd”>
< jdo>
< package name = “business.model”>
< class name = “Book” >
< field name=“picture” persistence-modifier=“persistent”/>
< /class>
< /package>
< /jdo>
如果其它模块通过getPicture获得对象,并在JDO不可感知的外部,修改对象,则变化不会存储,较好的办法是修改setPicture方法,如下:
public void setPicture(Object pic){
JDOHelper.makeDirty(this, “picture”);
picture = pic;
}
并通过setPicture方法来更新数据。
JDO的“makeDirty”方法,主要负责通知JDO实现,可持久化类Book某个实例(this)的“picture”字段发生了变化。
集合
可持久类的字段引用为集合时,按照JDO规范,强制支持java.util.HashSet,对HashMap、HashTable、TreeMap、TreeSet、LinkedList、ArrayList及Vector的支持对JDO实现而言是可选的,通过PersistenceManagerFactory的supportedOptions方法获得实现特性。
数组
如果可持久类的引用是数组类型,当数组单元发生变化时,需要调用“makeDirty”来通知JDO实现,该实例的数组引用内容发生了变化。
与引用是非可持久类实例不同,不需要进行JDO的元数据声明。
继承
如果使用可持久性,一般继承的子类与父类都为可持久类,以减少系统复杂性,这时需要在子类的元数据中指出其可持久超类,如下:
可为非持久类扩展持久类,或可为持久类扩展非可持久类;这两种情形JDO实现都将忽略非可持久类的字段部分,而不保存到数据库。
JDO的一些不足之处
JDO对数据的持久化技术相比于成熟的SQL,还有不足之处,这些不足在某些情况下将可能会影响数据处理部分的设计实现。
以下列举了常用数据访问的必要功能
查询增强
如字符串不支持通配符、大小写比较;
不支持聚合操作,无法实现MIN、MAX、SUM和AVG;
不支持投影操作,JDO查询返回为对象,而不像SQL那样返回字段;
不支持联合、交叉(UNION/INTERSECT);
不支持JOIN、IN和EXISTS;
企业应用探究
由于JDO采用面向对象的持久化处理技术,从而为解决企业业务系统的持久化问题提供了一个新技术解决方案。但是先进的未必就最适用。在某些应用场景下,需要结合各种因素,采取灵活的策略。
面向对象与面向记录
现在大多业务系统都采用面向对象分析设计,这就需要每个应用系统都自行实现将对象映射成记录,并存储到数据库中,而有JDO这样的面向对象的持久化技术,在某种程度上解放了这种转化设计的不规范性,进而获得相对更优的系统结构;另一方面,一个业务系统的数据持久化,一般都有这样的过程:对象层->记录层->物理层,JDO无疑使分析设计人员从记录层的苦海中解脱出来,从而更加专注于对象层,这对开发人员无疑是一个令人欢欣鼓舞的技术。
JDO并不能完全代替JDBC。
根据经典的“8-2原理”,如果用JDO来解决80%的问题,余下的20%由JDBC来实现,这种相互补充,各取所长的策略,是一个很有效的办法。
这样一方面可以获得较好的结构及提升开发质量,另一方面解决了JDO的某些技术不足,并可根据以后的技术变化,再做适当转化。
性能问题
JDO与JDBC究竟谁的性能更优,目前还没有一个权威、且令人满意的答案。但对于一些JDO实现而言,通过采用缓存机制,使得性能有了较大提高。
发表评论
-
转发(Forward)和重定向(Redirect)
2009-12-01 10:55 2862request.getRequestDispatcher(&q ... -
Hibernate 简单介绍与图示原理
2009-04-29 16:22 8141、Hibernate 介绍Hibernate 是一个开放源代 ... -
Java Reflection (JAVA反射)
2009-04-28 23:10 639Reflection 是 Java 程序开发语言的特征之一,它 ... -
java中覆盖、重写与重载的区别
2009-04-28 21:40 2141初次见到这两个单词并 ... -
抽象类与接口的区别
2009-04-27 20:36 628abstract class和interface是Ja ... -
java垃圾收集算法
2009-04-27 18:08 6671.垃圾收集算法的核心思想 Java语言建立了垃圾收集机 ... -
java 继承类 变量、静态变量、构造函数执行顺序
2009-04-27 18:06 936class C{ static int prt(int i){ ... -
Java多线程编程总结
2009-04-27 17:42 774一、认识多任务、多进 ... -
WWW服务器讲解
2009-04-23 23:27 808HTTP 1.1 协议 当欧洲高等 ... -
怎么计算WEB服务器的最大负载量
2009-04-23 23:24 1178【导读】用动态反馈负载均衡算法考虑服务器的实时负载和响应情况, ... -
Tomcat中用web.xml控制Web应用详解
2009-04-23 23:13 6481 定义头和根元素 部署描述符文件就像所有XML文件一样,必 ...
相关推荐
综上所述,将JDO技术应用于Struts框架不仅可以充分发挥Struts框架在Web应用开发方面的优势,还可以利用JDO技术在数据管理和持久化方面的特点,实现更加高效和灵活的Web应用开发。通过构建一个多层体系结构模型,可以...
随着互联网技术的发展和企业需求的不断增长,J2EE(Java 2 Platform Enterprise Edition)作为一套全面的企业级应用开发平台,在过去几年中得到了迅速的发展,并逐渐成为企业级应用开发的事实标准。J2EE平台提供了...
工程师将有机会与行业内顶尖的技术团队合作,接触包括大型分布式应用服务器集群、分布式缓存算法、数据访问层、分布式会话管理、用户资料服务、消息服务、企业服务总线(ESB)、计算集群(如Hadoop)、统计趋势分析...
在基于JSP的Web应用开发中,选择合适的数据库连接技术对于提升应用性能和可维护性至关重要。JDBC作为基础的数据库连接技术,虽然功能强大,但在实际应用中通常会被更高级的技术所替代或封装。JDO和Hibernate等技术因...
它以其“依赖注入”(Dependency Injection, DI)和“面向切面编程”(Aspect-Oriented Programming, AOP)为核心理念,极大地简化了企业级Java应用的开发工作。这个PPT将带领我们深入了解Spring框架的基础和核心...
### 基于Hibernate的效率查询的研究和应用 #### 摘要 本文详细探讨了当前流行的Hibernate映射框架,并结合某通信企业的电子运行维护系统(E2OMS)的实际开发过程,提出了一个基于Hibernate的数据持久层解决方案。该...
- **应用范围**:适用于企业级应用开发。 #### 目标13:掌握XML处理API - **API选择**:JAXP、JDOM、DOM4J、JAXR等。 - **应用案例**:XML文档解析、转换及验证。 #### 目标14:学习Web服务API - **技术要点**:...
**JTangEJB二次开发手册** 是一份专门用于指导开发人员如何基于JTang应用服务器的EJB模块进行二次开发的技术文档。该文档旨在帮助开发者更好地理解和掌握JTangEJB模块的核心功能,并通过具体的整合实践来扩展其功能...
《构建Spring 2企业级应用》是一本深入探讨Spring框架在企业级Java应用程序开发中的应用的专业书籍。本书由Interface21公司与Bram Smeets和Seth Ladd共同撰写,旨在帮助读者掌握如何利用Spring Framework 2.x版本...
Java持久对象(Java Data Objects,简称JDO)是一种用于Java应用程序的持久化框架,它提供了一种透明的方式来管理和存储Java对象到数据库。在"JdoExamples"项目中,我们可以看到一个完整的JDO应用实例,用于演示如何...
这本书特别适合软件架构师、高级开发者和咨询顾问阅读,它不仅提供了领域驱动设计和测试驱动开发的最佳实践,还深入探讨了如何在轻量级Spring、Hibernate和JDO技术的基础上构建高质量的Java企业应用。无论是初学者...
随着技术的发展,不断有新的框架出现,如Spring Data JPA等,这些框架持续优化并完善ORM的概念,为Java开发带来了极大的便利。了解并熟练掌握这些框架,对于提升Java开发者的技能和项目效率至关重要。
Spring框架是一个全面的企业级应用开发框架,它通过一系列模块化的组件来支持不同的应用场景和技术需求。Spring的核心价值在于提供了一种简洁的方式来解决企业级应用开发中的常见问题,比如依赖注入、面向切面编程、...
它的主要目标是简化现有的持久化开发工作,并且整合ORM (Object-Relational Mapping) 技术,结束不同ORM框架如Hibernate、TopLink、JDO等各自为政的局面。 #### 2. JPA的发展背景与目标 - **背景**:JPA是在充分...
4. **Web MVC 框架**:Spring 2.0 对 Web 层进行了重大改进,提供了更丰富的视图解析器、拦截器等机制,使得 Web 应用程序的开发更加灵活。 5. **数据访问层**:增加了对 JDBC、Hibernate 和 JDO 等持久化技术的...
【EJB系统开发实战录】是一本深入探讨Enterprise JavaBeans(EJB)技术的实践性教程,主要针对Java企业级应用开发。EJB是Java平台企业版(Java EE)的一部分,用于构建可扩展、安全且可靠的分布式应用程序。本书旨在...
还深入到了JAVA的高级特性、框架使用、数据库技术、分布式对象处理、中间件技术、XML处理、WebService构建、轻量级应用程序框架的掌握、J2EE技术的熟练应用以及企业级JavaBeans的管理等多个方面。以下是对这些关键...