了解一个良好数据层的应有的特质
Java Data Object(JDO) 标准提供了一个统一的、简单的、在Java application object和数据库间透明的接口,它是数据处理的一个革新,在本文中作者将会讨论我们所碰到的持久性数据的处理、特性等问题,最后介绍JDO这种解决方案
数据和计算一样古老,现在随着面对对象语言的兴起,面向对象的数据也变得深入人心起来。目前大多数先进的、重要的应用程序都使用面向对象的数据结构。另一方面 大部分的数据库系统仍然是关系型数据库,虽然面向对象的数据结构对很多应用必不可少,但我们能仍然要考虑很多原有系统的需要
本文讨论的是在传统中间件环境下,比如J2EE中,JDO是如何解决持久性数据的问题。本篇文章是一篇有关JDO的介绍,而并非具体的教程,面向的是应用程序的开发者(熟悉Java开发、对象数据库和关系型数据库),而不是JDO的实现设计人员
需要透明的存储层?
以下列举了为什么我们使用面向对象的数据:
1.抛开数据存储的细节,建立简单、明了的面向对象的API来处理数据。我们不关心存储的细节和数据库中内部的数据含义,而是关心数据间的关系、对象含义或其他的一些逻辑。为什么我们要处理数据存储中的低级结构,比如表、列,并来往返回的存取他们,我需要的是更关注复杂逻辑应用中所直接所应用的数据形式
2.我们想要使用即插即用的方式来处理数据:当改变数据库时不需要更改一行代码,甚至也不要修改很多的配置。换句话说,我们需要一个以Java object为基础来存取数据的工业标准,就如同象JDBC那样是访问SQL数据的工业标准.
3.我们需要即插即用的方式来处理不同的数据视图,也就是说我们可以以最小的改动完成从关系型数据库向面向对象数据库的的转变。听起来不错,但在实际使用使用中,这并不重要。
以上的3个原因需要我们定义一个存储框架来提供对象和关系型数据库之间高级别的Java API,这些API的生命周期要长于运行环境(JVM)的生命周期,这样的API应该具备以下的特征:
简易
最少的嵌入
透明,意思是该框架需要隐藏数据库实现
协调一致,简单的API用于保存、取出、更新
支持事务,需要定义出于数据对象的相应事务语义
既支持可治理(服务模式应用),也支持非可治理(单机)的环境
支持必要的附加功能,比如缓冲、查询、主键生成器、Map工具
下面,我们来详述这些特征
简易性
简易性之所以被我放在一个这么高的位置,是因为,对开发分布式应用来说已经很复杂了,很多软件项目的失败正是由于它们过于复杂的治理方式。简单不意味着过分简化。只要能满足开发者的工作就可以了
最少的嵌入
每个存储系统总是会嵌入一定的内容到程序代码中,良好的数据层应该最小化这种嵌入,从而提高可移植性
我这里指出的是嵌入是指:
所有需要嵌入程序中的有关存取相关的代码(实现一些存取接口或类似存取的操作),这种嵌入的情况同时也出现一些ODBMS中(object-oriented database systems),相比RDBMS它会少一些,嵌入的多少和不同ODBMS实现商的实现有关
透明性
数据存储层的透明性概念很简单:所有的应用程序使用与数据库类型无关(数据库类型透明性)、数据库提供商无关(提供商透明性)的统一API。这种特性通过隐藏数据库实现细节大大提高了代码的可维护性和扩展性.比如对操作那些流行的关系型数据库,可以不像JDBC那样编写繁杂的SQL语句并记住列的顺序.事实上你都不需要了解SQL或任何关系型概念,因为它们都太与数据库的实现相关了,透明性或许是数据层最重要的特性了
统一的、简洁的API
数据存储层API可以归纳为以下的一系列操作
作用于基础类(first-class objects:String,Integer 等)的基本CRUD(create, read,
update, delete)操作
事务治理
应用程序对象和数据对象同一性控制
缓冲治理(比如刷新和释放治理)
查询的创建和执行
下面看一个数据层的API的例子:
public void persist(Object obj); // Save obj to the data store.
public Object load(Class c, Object pK); // Read obj with a given primary key.
public void update(Object obj); // Update the modified object obj.
public void delete(Object obj); // Delete obj from the database.
public Collection find(Query q); // Find objects that satisfy conditions of our query.
支持事务
一个良好的数据层需要一些基本的事务功能:开始、提交、回滚事务(start, commit,roll back),这里有一个例子:
// Transaction (tx) demarcation.
public void startTx();
public void commitTx();
public void rollbackTx();
// Choose to make a persistent object transient after all.
public void makeTransient(Object o)
注重:这样的事务功能划分只应用在非治理环境(nonmanaged environments,单机),对可治理环境,内建的事务的治理器通常已经具备了这些功能
可治理环境,例如一个J2EE应用服务器,数据层都会和这些应用服务器的EJB容器和其他一些相应的服务(比如JNDI和事务治理器),协同工作
查询
这样的API还必须具备数据的查询能力,它应该是稳定、有效、易用的。这样的API使用Java object 而不是SQL 表或其他的传统数据表示参数作为自己的行为语言
缓冲治理
缓冲治理主要关系到应用的性能,一个完善的数据层应该提供完整的缓冲功能API,比如锁定级别(locking levels:行锁,整表锁,列锁)、延迟加载(lazy loading:指一开始数据不被加载,在第一次需要时,才加载)、缓冲清除策略(eviction policies: 指如何将过期数据从cache中clean掉,或写回磁盘的策略)
译者注:以上的3点也就是讲述缓冲如何更新数据、如何加载数据,如何把不用的数据从cache中移走
主键生成器
产生标注数据的唯一性标识是一个很普遍的功能,每个数据层都会提供一个拥有各种算法的主键生成器,有关主键的生成已经是一个研究很成熟的问题,有很多主键生成的算法
Mapping(映射),对关系型数据库而言
使用关系型数据库,会有数据映射的问题:需要把对象映射成表、映射关系(比如对依靠和引用要映射成表或字段的关联。这点对复杂的对象模型尤为重要.有关对象-关系的模型已经超出了本文的范围,但它很重要,请参考文尾的有关资料
如下的一些附加功能不是数据层所必须的,但他们会简化开发员的一些工作:
图形的映射工具
代码生成器:自动生成DDL(data description
language)来创建数据库表或根据DDL产生相应的Java代码和映射文件
主键生成器:支持多算法比如:UUID, HIGH-LOW, 和 SEQUENCE
支持二进制大字段对象(BLOBs)和文本型大字段对象(CLOBs)
自我引用关系:比如一个Bar对象引用另一个Bar对象
支持原始sql语句 :传递SQL查询
范例
下面的例子将会显示如何使用数据层的API,加设下面一种情况:一个公司有一个或多个位置,每个位置有一个或多个用户,这样我们来看如下的程序代码:
PersistenceManager pm =PMFactory.initialize(..);
Company co = new Company("MyCompany");
Location l1 = new Location1 ("Boston");
Location l2 = new Location("New York");
// Create users.
User u1 = new User("Mark");
User u2 = new User("Tom");
User u3 = new User("Mary");
// Add users. A user can only "belong" to one location.
L1.addUser(u1);
L1.addUser(u2);
L2.addUser(u3);
// Add locations to the company.
co.addLocation(l1);
co.addLocation(l2);
// And finally, store the whole tree to the database.
pm.persist(c);
另一种情况,你可以这样查询雇员Tom:
PersistenceManager pm =PMFactory.initialize(...)
Collection companiesEmployingToms = pm.find("company.location.user.name = ´Tom´");
对于关系型数据库,你必须创建一个mapping文件,如下
<!DOCTYPE mapping PUBLIC ... >
<mapping>
<class name="com.numatica.example.Company" identity="companyID" key-generator="SEQUENCE">
<cache-type type="count-limited" capacity="5"/>
<description>Company</description>
<map-to table="Companies"/>
<field name="companyID"type="long">
<sql name="companyID" type="numeric"/>
</field>
<field name="name" type="string">
<sql name="name" type="varchar"/>
</field>
<field name="locations" type="com.numatica.example.Location" collection="arraylist">
</field>
</class>
<class name="com.numatica.example.Location "identity="locationID"
key-generator="SEQUENCE">
<cache-type type="unlimited"/>
<description>Locations</description>
<map-to table="Locations"/>
<field name="locationID" type="long">
<sql name="locationID" type="numeric"/>
</field>
<field name="name" type="string">
<sql name="name" type="varchar"/>
</field>
<field name="company" type="com.numatica.example.Company"required="true">
<sql name="companyID"/>
</field>
</class>
<class name="com.numatica.example.User" identity="userID"
depends="com.numatica.example.Location" >
<cache-type type="count-limited" capacity="200"/>
<description>User</description>
<map-to table="Users"/>
<field name="userID" type="integer">
<sql name="userID" type="numeric"/>
</field>
<field name="location" type="com.numatica.example.Location"required="true">
<sql name="locationID"/>
</field>
<field name="name" type="string">
<sql name="username" type="varchar"/>
</field>
</class>
</mapping>
持久数据层的工作围绕着以下这些方面:
查找相关对象的组
保持应用对象的一致性
治理数据的标识(主键)
按一定的顺序储存每一对象
提供缓冲治理
提供合适的事务范围(我们不想只把对象树的一部分存储起来)
提供用户可选的锁定模式
一般有以下几种解决方案
1.使用JDBC API,自己完成其它的工作
2.使用适合的对象-关系映射工具或者直接使用对象数据库(ODBMS)
3.使用J2EE中的CMP-EJB(container-managed persistence entity bean)解决方案
4.Java Data Objects (JDO)解决方案
目前还没有一种解决方案对所有的需求都可以适合,所以在我们主要介绍JDO之前,我们先浏览一下其他的几种方案
自己编写中间层代码接口
过去,大部分开发人员使用关系型数据库作数据存储,自己开发数据的连接层应用.这通常离不开2种技术JDBC和SQLJ,后者可能应用少一些,它们都需要应用一些SQL技术,并且这两种方法都具有数据库相关的不透明性,最后会形成难于维护和不易扩展的代码
一些公司尝试自己开发数据存贮层,但是这种工作复杂庞大,除了大型的专业公司组织,一般的公司又何苦重复这种工作
使用对象-关系映射工具:
O/R工具已经被经常使用了,这种方法也比较成熟了,有很多O/R工具的提供商,业界的领导者是WebGain的TopLink以及Thought公司的CocoBase,还有ObjectMatter的Visual Business Sight Framework(VBSF)
虽然大多数O/R映射工具提供了简单一致的API,简化了工作,而且大多数O/R映射工具提供了较少嵌入,VBSF在这方面作的的确很不错,同时它们也提供了一定的透明性,弥补了关系型数据库的一些不足,但是他们都有各自专属的API,不同的提供商间的映射技术区别较大,技术迁移问题很大.而且你还要自阿开发上多加一笔软件许可费用
使用对象数据库:
使用对象数据库甚至还不使用O/R映射工具,假如使用这样的产品你可能会被一个数据库产品锁死,而且数据存贮系统的变换肯定不是件轻易的事,再加上几个主要的ODBMS提供商都公布会支持即将出现的JDO标准,所以这样方案有待提高
J2EE的 CMP 方案
使用J2EE的 CMP 方案会受制于J2EE规范和应用服务器厂商的限制,在EJB 1.1 CMP规范中就缺少很多的高级关联,新的CMP 2.0规范有很大进步,但EJB在代码维护和性能上还是有不足
JDO方案:标准、开放、透明的应用于Java的数据层
现在有两个都以JDO命名的标准:Sun的 JDO和Castor JDO.
Sun的 JDO
Sun的 JDO 是由Java Community Process(JCP)制定开发的一套高级别的API规范,以及一个参考实现.在1999.7 JDO规范请求(JSR-12)被通过,并在同一时间发布最终提议草案.除了这里规范外,它还包含了一个参考性的实现范例,它是在2001年第二季度完成的1.0 beta版,它使用一般的文件形式实现存储
规范
SUN的 JDO规范定义了一个在应用程序对象和传统数据库间的简单、透明的接口.它已经引起了数据库厂商的爱好,一些厂商甚至已经开始有所动作,但是由于该标准还在草案阶段,目前只有一两个beta实现,还没有厂商提供完整功能的产品
虽然Sun的JDO提供的是透明的存储,但是ODMG(Object Data Management Group)的数据存储接口和几个主要的ODBMS提供商还是很大地影响这个规范。比如,映射机制格式(按XML格式定义)脱离了实现提供商而定义自己的格式,这限制了可移植性,在对抗JDO
该规范包含了以下几个方面
含有事务的存储
传统对象和J2EE的交互
基于Java表达式的数据查询
参考实现范例
Sun的JDO包含了一个使用一般文件功能有限的实现,它答应存储、取出、浏览以及事务性地更新存储实例(无查询功能)
有关Sun JDO的第三方的实现可以分成两类
非数据库厂商
SolarMetric Kodo JDO
PrismTech OpenFusion JDO
TradeCity Cybersoft´s Rexip JDO
主要的数据库厂商
Versant Judo
GemStone Systems
IBM´s Informix
Poet Software
Excelon (formerly Object Design)
Castor JDO
Castor JDO 是一个有Exolab赞助的从1999开始的一个open source 项目,尽管和Sun的JDO有一样的名字,但它们并不兼容,但是也相差不大。Castor JDO非凡专注于关系型数据库,所以并不支持存储类型的透明性。它是open source的,没有使用费用和专有权,但由于它的开发团队相对较小,即使比Sun的JDO标准早,但它的优势不会很长了,但Castor JDO仍然在解决数据层问题上作出了很多工作,也值得仔细研究
JDO:强壮的数据层
本篇文章提供了有关对象-关系问题的概览、列举了一个良好数据层的特质。当现在还只有很多专属的O/R映射工具的时候,我们更需要一个标准、开放接口的、多厂商支持或开放代码的数据层实现,目前有两个这样的规范Sun的JDO 和 Castor JDO.
在本系列文章的第2部分,我们将会介绍有关这两种JDO的具体信息:它们如何解决数据层标准性、或者还有没解决的问题。我们还会深入比较JDO和其他一些数据层技术的差别,比如EJB CMP 2.0
About the author
Jacek Kruszelnicki is president of Numatica Corporation, an information technology consulting firm providing eXPertise in information-systems strategy development, analysis, and planning; software development; and training. Jacek (pronounced Yatsek) received his master´s degree in computer science from Northeastern University in Boston, Mass., and has more than 15 years´ experience delivering maintainable, large-scale, distributed enterprise solutions.
英文原文:Persist data with Java Data Objects, Part 1
转载自:http://mag.javadigest.net