贺JDO2.0计划启动
近日,欣闻Sun公司正式加入了JDOCentral.com作为其Charter Member之一,表明了Sun公司对JDO的正式支持和推动。以往,Sun虽然提出了JDO规范,但在正式支持方面总是做得不够,感觉好象是因为对其EJB体系会造成冲击,所以一直只是半推半就地提供有限的宣传,主力推广JDO的还是JDOCentral.com这个公益网站。不过现在,JDO规范已经提出来有近一年半了,陆续也有很多优秀的产品涌现出来,看样子即将形成一股新的旋风,Sun看到时机成熟,这时还不跳出来,更待何时!于是我们也很欣喜地看到,Sun正式加入了JDOCentral,并且,开始了JDO2.0计划的准备工作。
信息来源:http://www.theserverside.com/home/thread.jsp?thread_id=20875&article_count=37
我们已经提到,JDO1.0已经提出有一年半,但似乎大众的接受程度还不够,没有很多应用开发公司表现出足够的热情。除了Sun的推动不够这个原因之外,这也是与与JDO1.0的局限性是有关的。我们期待JDO1.0能够解决大多数中小规模数据库应用的开发,也就是能够基本取代JDBC,但是不支持映射和数据库统计功能是JDO1.0的最大缺陷。我就一直期待JDO2.0能够解决这些问题,至少可以针对JDBC专门提供一组optional API,这样也可以不影响JDO在其它类型数据库(比如文件、XML和OODB等)中的应用。总地来说,JDO1.0能够满足我们开发数据库应用中的多数需要,只是加上这些功能将会更为方便。
我们现在来看看JDO2.0将给我们带来什么。实际上,在JDO1.0规范中已经在最后一章提出了一些已经为多数人所关心的功能,但由于想法还不成熟,或者大家意见不一致,还有待实践的进一步验证,于是只好放到JDO2.0再去规范化。因此,我们有理由相信JDO2.0的议题首先会包括这些内容,至少大部分内容会被包含。这里,我简单地解释一下JDO1.0规范中推到下一版的议题有哪些:
嵌套的事务
事务的支持是一个数据库必须提供的功能,但实际开发中,我们常常会需要多级的事务,中间的某个操作的失败不会引起整个事务的回滚,而只是将一小部分操作进行回滚,再采取另外的操作。JDO2.0将会对此进行规范化,当然,可能是作为一个可选的特性,让厂商选择是否实现,不过一旦实现,用户就可以通过规范的API去执行嵌套的事务处理。
比如,我们在编写业务逻辑的时候,可能会有很多个逻辑方法,每一方法都需要对数据对象进行更新操作,也就是说,需要在方法里面使用一个事务。如果其中一个方法有可能被另一个方法调用,那么在JDO1.0可能会出现“事务已经开始”的异常,于是,我们只好用下面的代码来编写每一个逻辑方法,以保证它们之间的相互调用不会出错:
public void logicalOperation1() {
Transaction tx = pm.currentTransaction();
boolean newTx = !tx.isActive();
if(newTx) tx.begin();
//这里做一些数据对象的更新操作
if(newTx) tx.commit();
}
在JDO2.0中,我们就不必担心这个问题,每一方法只需要简单地开始一个事务,进行数据操纵,然后提交,就行了。
事务保存点
这个实际上是JDBC3.0提出的功能规范,它在一个事务中可以让你回滚到某个指定的点,而不是回滚整个事务。如果底层的JDBC驱动支持JDBC3.0规范,那JDO2.0将会利用这个特性来给应用代码提供更强的控制。事务保存点与嵌套的事务都是事务处理中的高级功能。这里提一下,JDO之下的底层数据库不一定是JDBC数据库。
跨PersistenceManager的对象操纵
即定义标准的接口来对不同的PersistencManager管理的对象之间的关系进行操纵和管理。这一点非常有用,可能可以完成不同的数据源之间的对象关系处理,比如一个存在于MySQL中的对象含有一个引用指向一个Oracle中的对象,JDO可以自动地完成两者之间的引用调用,不必在应用代码中进行额外操作,使应用代码更简单,更透明化。
调用增强器的标准API
JDO2.0会定义一个接口方法来让应用程序直接调用增强器增强某个类的类代码。这一点可以保证应用开发过程在增强时的统一性,不受厂商影响。此外,可能可以通过此功能在某些J2EE服务器中做出符合标准的动态增强器(如特定的ClassLoader),以使增强这一步骤对开发过程的影响更小。
预读数据API
我们在写应用代码的时候,只需要查询出一个对象集合,然后通过访问其属性来触发底层的数据库读取操作,虽然很透明,但有时候得到的性能并不是很好,比如读取1000个对象,可能会造成1000多次数据库的数据传输。再比如,有时候我们需要访问一组对象的某两个属性,但JDO可能会将所有的属性都读出来,也会造成一定的性能损失,在这一点上,比JDBC要慢。而另外一些情况下,我们需要同时访问一组对象所相关的另一组对象,而JDO默认都是对被引用的其余对象进行延迟调入的,在这种情况下,数据处理时间会有所延长。因此,我们希望在特定的JDO查询之前,我们可以给JDO一点提示,让它知道如何能够最有效地得到我们需要的数据。
JDO2.0可能会定义一些API来让程序告诉JDO该采取什么策略在马上进行的一个查询中读取数据,以使应用程序在特定的代码段中得到最好的性能。
BLOB/CLOB类型的支持
目前为止,JDO产品可以选择不同的方式来将byte[]类型映射成java.sql.Blob,或者将字符串或者其它数据映射成java.sql.Clob,不过具体的映射方式不会作规范化,也许会导致不同的产品运行同样的应用性能有所差异。
自动的(双向)对象关系维护
这一点是我个人认为最有用的。我们在写CMP的EJB2.0时,会感到其管理的实体之间的双向关系非常有用,而JDO1.0出于各种考虑,暂时没有将这一点写进规范中,而只是在JDO2.0中再作规定。这一功能对多对多关系尤其有用。比如我们有两个类:教师和课程,它们有一个多多对应的关系,一个教师可以教多个课程,而一个课程也可以由多个教师来教,这一关系就是一种多多对应关系。代码如下:
public class Teacher {
String name;
Set teachingCourses;
}
public class Course {
String title;
Set byTeachers;
}
在这两个类中,Teachers.teachingCourses与Course.byTeachers是一个双向的多对多关系,如果我们调用someTeacher.teachingCourses.add(someCourse),那么someCourse.byTeachers就会包含someTeacher,这一点由JDO去保证,不象JDO1.0要求用户自己写代码与维护这一点。
在这一点上,目前只有JDOGenie这个产品提供了这一特性,作为一个厂商扩展功能。
虚拟机退出时自动关闭PersistenceManagerFactory
JDO2.0会定义一个具有一定权限保护的方法,允许厂商或者特殊的用户代码进行调用,这个方法可以按合理的顺序关闭一个PersistenceManagerFactory涉及的各种底层数据库资源,以防止资源被持久占用而造成系统漏洞。这样一来,我们在写应用程序时就不必考虑过多的清理操作。
举例来说,我们写一个基于JDO的GUI程序,我们可以在一开始就打开一个PersistenceManager,然后在程序中简单地使用,不用关闭,不用清理相关的查询结果,当程序退出的时候,底层的JDO可以自动地将涉及到的JDBC资源清理干净,不造成资源泄漏。在JDBC应用中,如果采用JDBC打开了一些ResultSet或者Statement资源而不关闭,在程序退出后,这些资源永远不会得到释放,最后你再次访问数据库时将看到类似“打开的文件句柄超过系统最大数量,不能执行操作”的错误信息。
大小写不敏感的查询
当我们对采用字符串提供一个toLowerCase()之类的方法后,实际的查询将不会受大小写的影响,达到某些特别的查询目的。JDO2.0会给出类似的解决方法。
查询中的字符串转换
在查询过滤串中将会有一些String(整形值)和String(浮点表达式)之类的类型转换方法,以提高查询的灵活性。
只读属性
一些底层的数据源可能对数据更改有限制,我们将可以在JDO的元数据中对某些类的某些属性写上只读标记,这样可以在JDO层禁止对该属性的更改,如果应用中改了这些属性将得到一个异常。这种机制将尽早地提醒用户不能更改某些属性,比数据源级的错误提示更有利于排错和性能优化。
枚举模式
通常,我们会有一些数据是有一定的范围限制的,比如定单状态、客户类型等等,这些数据只会在几个有限的值只取值,在非数据库的Java程序中,我们可以采用类常量来表示,但一旦应用到数据库中,我们不得不做很多检测和控制来达到这一目的,并且实际存储的值一般是整数。
JDO2.0将会对这一常见的功能进行规范化,使我们用JDO一样能简单地存储枚举数值。比如:我们对定单规定几个状态:
public class OrderStatus {
private int orderStatus;
private OrderStatus(int status) { this.orderStatus = status; }
public static OrderStatus NEW = new OrderStatus(1);
public static OrderStatus CONFIRMED = new OrderStatus(2);
public static OrderStatus PAID = new OrderStatus(3);
public static OrderStatus DELIVERED = new OrderStatus(4);
public static OrderStatus CLOSED = new OrderStatus(5);
}
这样,我们在其它类中就只能使用order.status = OrderStatus.NEW;之类的语句来设置定单的状态了,而JDO会自动维护数据库中的对应值。当然,我们也可以在数据库中采用字符串来表示状态值,只须在OrderStatus类中采用一个字符串型的内部属性,并将构造器改为字符串参数即可。
动态内部类的支持
JDO2.0将支持动态的内部类,其主类也应该是可存储的,并且在内部类对象与主对象之间会有一个自动实现的多对一关系,这样一来,我们可以实现一些具有依赖性的数据类型。比如一个客户对象具有某些高级信息,我们想放到另一个内部类中,可以这样写:
public class Customer {
String name;
public class Info {
String idcard;
}
}
这样,当我们使用new someCustomer.Info();后,JDO会为someCustomer对象保存一个相关的Info信息。当然,也可以是多个,通过特定的API可以得到某个Customer对象相关的所有Info子类对象。
对部分属性的查询
在JDO1.0规范中定义的查询的返回值都是某个类的实例集合,但我们有了EJBQL的经验后,我们会很想念其中的ejbSelectXXX方法,可以只选取某个类的实例的部分属性集,这样可以节省资源,提高性能。JDO2.0会提供类似Query.setResult(String projection)的方法,然后定义一个临时的类,其中包含对应的属性,这样来得到返回的属性集。
LogWriter支持
这一功能基本上是为JDO厂商提供的,让他们有一个标准的操作日志输出方式,不象现在各个厂商输出自己的SQL调试信息时八仙过海,各显神通,结果是用户使用不同产品时得进行不同的设置才能控制这些信息的输出,麻烦。
以上就是JDO1.0中提到的将会在2.0规范中定义的内容。此外,个人认为,还有一些实用的功能也是JDO2.0需要进行规定的,比如动态的类增强,基于SQL92标准的数据库统计功能等等。
好了,JDO2.0的启动已经临近,让我们拭目以待,看看JDO2.0将会给我们带来怎样的惊喜!同时,我们也祈祷,JDO2.0不会象1.0那样一团争论,三年方休!
本文的版权属于笔者本人,但欢迎转载,前提是注明出处和原作者。另外,欢迎在我的专栏中查看我的另几篇文章,并提出宝贵意见!
本文地址:http://com.8s8s.com/it/it17519.htm