`
TrampEagle
  • 浏览: 23158 次
  • 性别: Icon_minigender_1
最近访客 更多访客>>
社区版块
存档分类
最新评论

JDO技术分析及如何进入企业应用的研究

阅读更多
本文引自:http://www.cn-java.com/target/news.php?news_id=3340
出处 Java研究组织 曹振新

JDO(Java Data Object)是JCP中较早开发出来并形成规范的JSR12,该规范对数据的持久化存储进行了一系列规范,并已有众多的商业产品和开源项目是基于该规范。作为一种需要引起重视的技术,研究并探讨其企业应用可行性是十分重要的。

前言

在企业级的应用开发中,常需要有良好的持久化技术来支持数据存储。通过良好的规范或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文件。


encoding = “UTF-8”?>










并通过字节码增强工具(本例采用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描述文件中,还需提供如下信息:


encoding = “UTF-8”?>



identity-type=“application”
objectid-class=“BookKey” >
primary-key=“true”/>







其中“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.getPersistence
ManagerFactory(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.getUser
Transaction().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不是一个可持久类,故声明如下:







persistence-modifier=“persistent”/>







如果其它模块通过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的元数据声明。

继承

如果使用可持久性,一般继承的子类与父类都为可持久类,以减少系统复杂性,这时需要在子类的元数据中指出其可持久超类,如下:


<
class name=“TechBook”
persistence-capable-superclass=“Book”/>




可为非持久类扩展持久类,或可为持久类扩展非可持久类;这两种情形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实现而言,通过采用缓存机制,使得性能有了较大提高。

跨数据库

使用JDO的系统能更好地进行数据库移植,甚至可以在对象数据库上运行;当然JDBC处理层如果完全遵循SQL-92标准,也同样具有很好的跨数据库能力。
分享到:
评论

相关推荐

    JDO持久化技术应用于Struts框架的模型.pdf

    ### JDO持久化技术应用于Struts框架的关键知识点 #### 一、引言 在现代Web应用开发中,高效且灵活的框架和技术对于提高开发效率至关重要。Struts框架因其优秀的架构设计,成为Java Web开发领域的首选之一。而Java...

    JDO原理及开发.doc

    《JDO原理及开发》文档详细介绍了JDO的基础知识和实际应用,对理解JDO的工作原理和开发模式具有极大帮助。通过学习,开发者可以更好地利用JDO来简化数据访问层的开发,提高开发效率,同时保持代码的可维护性和灵活性...

    JDO原理及开发实现

    Java 数据对象(JDO,Java Data Objects)是一种用于在Java应用程序中访问关系数据库的标准API。JDO 提供了一种透明的持久化机制,允许开发者直接操作对象,而无需关心底层数据库的操作细节。JDO 的核心理念是将Java...

    JDO原理及案例开发

    JDO 的核心思想是透明性,即在应用程序中处理Java对象,而无需关心它们如何在数据库中存储或检索。它通过元数据(Metadata)来定义Java对象与数据库表之间的映射关系。在运行时,JDO 框架负责对象的创建、读取、更新...

    J2EE中用EntityBean和JDO的优缺点分析

    本文主要对比分析了两种常见的持久化机制:EntityBean和Java Data Objects (JDO)。EntityBean作为J2EE的一部分,提供了一种标准的方式来处理数据的持久化,而JDO则提供了一种面向对象的持久化解决方案。 首先,...

    全面了解JDO数据库编程.rar

    前者适用于企业级应用,后者更适合小型项目。 7. **JDO查询** JDOQL支持复杂的查询操作,包括比较、集合操作、函数调用等。查询结果可以是对象列表,也可以是单个对象或值。 8. **性能优化** 了解何时使用延迟...

    全面了解jdo数据库编程

    JDO的主要目标是简化Java应用程序与数据库之间的交互,提供一种面向对象的方式来存取数据,从而避免了传统JDBC中的大量SQL代码和数据转换工作。 ### JDO规范 JDO规范定义了一组API,允许开发者以面向对象的方式...

    全面了解JDO第四部分

    在"JDO-Lido.pdf"、"j-jdo-a4.pdf"和"coreJDO-ch3.pdf"这些文档中,你可能找到更多关于JDO的具体实现细节、最佳实践以及案例研究。例如,"coreJDO-ch3.pdf"可能会详细解释如何配置和使用`PersistenceManagerFactory`...

    全面了解JDO第一部分

    传统的Java应用通常依赖于JDBC(Java Database Connectivity)来实现这一目标,但JDBC编程模式较为繁琐,而JDO则提供了一种更高层次的抽象。通过JDO,开发者可以使用普通的Java对象(POJOs,Plain Old Java Objects...

    jdo-java数据对象

    JDO是Java Community Process(JCP)的一部分,由Sun公司主导制定,目的是提供一个统一的标准来处理Java应用程序中的持久化问题。 JDO的优势在于: 1. 简化数据库访问:通过面向对象的方式,JDO使得数据库操作更加...

    jdo2-api-2.3-ec hive hdfs 所需jar

    总结,JDO2-API-2.3-EC在Hive和HDFS中的应用是大数据处理领域的一个重要实践,它通过提供高效、灵活的对象持久化方案,为大数据环境下的数据管理和分析带来了便利。开发者应深入理解和掌握JDO的核心特性,以便更好地...

    Struts2,Spring,JDO,AJAX on GAE

    Struts2、Spring、JDO(Java Data Objects)和AJAX(Asynchronous JavaScript and XML)是四个在Web应用开发中非常关键的技术。这篇博客“Struts2,Spring,JDO,AJAX on GAE”可能探讨了如何在Google App Engine (GAE)...

    jdo API 2.2

    在Google App Engine (GAE)环境中,JDO API 2.2是开发者常用的工具,它允许应用程序与GAE的数据存储服务进行交互。JDO 2.2提供了一种简单、灵活且强大的方式来管理对象的生命周期,包括创建、查询、更新和删除对象。...

    jdo2-api jdo2-api

    jdo2-api jdo2-api jdo2-api jdo2-api

    JDO上实践

    Java数据对象(JDO,Java Data Objects)是Java平台上的一个标准接口,它提供了一种在应用程序和持久性存储之间进行交互的方式。JDO的主要目标是简化数据持久化,允许开发者将Java对象直接保存到数据库中,而无需...

    JDO使用手册

    通过理解上述概念,开发者能够更好地利用JDO来提高应用程序的性能和可维护性。无论是简单的数据存储还是复杂的数据查询,JDO都能够提供强大的支持。希望本手册能帮助读者全面了解JDO,并在实际项目中有效地运用它。

    jdo-tutorial.pdf

    ### JDO 持久层框架教程 #### 安装 Devtool 插件 ##### 要求 在开始安装 Devtool 插件之前,请确保满足以下条件: ...JDO 是一种强大的对象持久化技术,它可以极大地简化开发过程中的数据存储和检索任务。

    jdo2-api-2.0

    Java Data Objects(JDO)是Java平台上的一个标准接口,用于访问关系数据库。"jdo2-api-2.0"是Sun Microsystems发布的JDO 2.0版本的API,它提供了...通过深入理解和熟练使用JDO,可以构建高效、可扩展的Java应用程序。

    JDO数据库编程

    coreJDO-ch3.pdf eigner_jdo.pdf JavaDataObjects_020321.pdf JDO 1.0.1规范-20030919-JDO_spec_1.0.1.zip JDO-Lido.pdf JDO技术的方方面面-JavaDataObjects-RobinRoos-1.0.pdf j-jdo-a4.pdf ...

Global site tag (gtag.js) - Google Analytics