java

位置:IT落伍者 >> java >> 浏览文章

Java数据对象(JDO)的前世今生


发布日期:2022年07月08日
 
Java数据对象(JDO)的前世今生

Java与数据库应用JDBC

Java发明以来在短短的几年之间迅速占领了从桌面应用(JSE)到服务器(JEE)再到小型设备嵌入式系统(JME)的应用开发市场其语言吸取了SmallTalk的一切皆对象的理念摆脱了C++的历史累赘简洁自由的风格赢得了很多开发者的喜爱从JDK开始Java成为实用的语言而不是被人观望的新品秀再经过JDK的大量增强(尤其是Collection Framework)JDK的虚拟机效率提升(HotSpot)JDK的融合百家之长(LoggingRegExpNewIO等)现在已经是成熟稳重颇显大家风范

在企业级市场上大部分的应用建立在数据库基础上数据是企业的生命传统开发语言包括面向过程的C面向对象的C++变种Pascal的Delphi(非常棒的语言我用过四年)面向数据的PowerBuilder等等先后在数据库开发的舞台上展现风姿Java当然不会放过这些于是出现了JDBC在JDBC的帮助下Java也迅速渗入数据库开发的市场尤其是面向企业服务器的应用开发

今天要谈的JDO与JDBC有非常密切的关系尽管JDO并不是只面向JDBC的数据对象包装规范下面先简单地介绍一下JDBC

关系数据库之百家争鸣ODBC

关系数据库的历史一言难尽我只能从我的接触经历和所见所闻简单地叙述一下最早的时候计算机还只在一些大型的研究机关露面并不是普罗大众可以涉及的苹果电脑将个人电脑引入民间再随着IBM的PC标准开放个人电脑逐步普及开来加上微软的DOS操作系统以及Borland的Turbo系列语言开发环境老百姓发现原来电脑可以做这么多事!后来出现了DBASE一个简单的关系数据库系统和SQL语言后来Borland看到了数据库的市场前景推出了Paradox(也是当今Delphi和C++Builder中仍然使用的Paradox)一举占领了民用数据库的大部分江山之后Borland干脆收购了Dbase后来又购买了InterBase将数据库市场的领先优势一直保持到Windows出现这时候微软在Windows被人痛骂之后顽强地推出以及更稳定的和WinAPI造就了个人电脑桌面操作系统的霸主地位在Borland未警觉的情况下购买了同样具有类Dbase数据库技术的Fox公司并迅速将其易用化形成了FoxBase后来演变成FoxPro逐渐超过了Borland成为个人电脑数据库的大户微软再接再励为简单易用而低负荷要求的数据库应用开发了Access赢得了广大开发人员的心当然同期的OracleSybaseInformix等商用数据库凭专注于企业级数据库技术成为高端的几位领军人物微软当然也想成为高端数据库供应商之一于是自行开发一套面向企业级应用的数据库不过很快项目夭折微软不甘心购买了Sybase的底层TDS技术包装成了SQL Server凭微软的高度易用性的特点也占领了不少市场

当市场上出现众多的数据库产品之后Borland和微软都发现自己拥有的数据库产品挺多市场也不小不同的产品给用户带来不同的配置任务不利于所有产品的推广于是两者纷纷开始制定数据库访问的规范微软推出了ODBC其面向开发人员的亲和性逐步获得了认可同时Borland纠集了IBM和Novell也推出了IDAPI数据库接口规范也就是今天BDE的核心不过后来Novell和IBM先后退出只剩Borland独力支撑不过Borland是一个技术实力雄厚的公司其技术一向领先于微软BDE的性能比初期的ODBC不知道要好多少倍后来微软偷师学艺把连接池等技术加到ODBC中在Delphi及其BDE在市场上风光无限的时候逐步赶了上来并有超过直到今天BDE仍是Borland的产品线上的数据库访问标准而微软如果不是将ODBC和多数数据库的客户端内嵌进Windows的话估计BDE仍是市场的赢家不过微软是玩弄市场的老手通过对操作系统的垄断其数据库产品和ODBC标准终究占据了多数开发市场

从optional pack到JDK的标准API

Java开始涉及数据库应用后Sun就极力制定Java的数据库规范JDBC API就是类似ODBC一样对数据库访问的底层协议进行最基本的包装然后形成一套统一的数据访问接口数据库连接SQL语句句柄结果集都带有ODBC的影子以方便配置为目的Sun极力推荐完全瘦客户端的TYPE 型JDBC驱动这是一个不需要安装数据库客户端的驱动规范是现在使用最多的当然为了保持与旧的数据库兼容JDBC规范中包括了专用于连接ODBC的TYPE 驱动和需要安装数据库客户端的TYPE 驱动以及可以由厂商在数据库服务端专门提供面向JDBC的服务的TYPE 驱动

JDBC最早出现时还不属于标准JDK的一部分而是作为一个额外包提供下载后来随着Java编写的数据库应用的的增多和JDBC规范本身的逐渐成熟JDBC终于成为JDK的一部分

JDBC目前最新的是版本还有正在讨论中的版本实际上在开发中使用得最多的还是中的API中主要增加了可双向滚动的结果集更新批处理等提高可用性和性能的API主要增加了连接池可更新的结果集等特性将在可管理性连接池规范化等方面再做改进

面向对象与数据库

现在的程序员没有不知道面向对象的作为接近真实客观世界的开发概念面向对象使程序代码更易读设计更合理在普遍存在的数据库应用领域开发人员对面向对象的追求从未停止过从八十年代开始就有很多公司和研究机构在进行着面向对象与数据库结合的研究

SmallTalkC与C++DelphiObject PascalJava

面向对象的语言最早有好几种雏形IBM的SmallTalk是其中最为流行的在SmallTalk中一切都是对象一切都是类它将面向对象的概念发挥到了极致面向对象的编程比起传统的面向过程的方式挺进了一大步使人们认识到原来软件可以这样写不过由于计算机基本结构与底层硬件体系和系统软件的限制SmallTalk还不能在理想的性能前提下推广到普通的应用上这一点暂时限制了SmallTalk的发展接着C语言的面向对象版C++出现了由于使用C语言的人很多C++很快成为面向对象编程的主流语言不过为了保证与C的兼容C++保留了很多面向过程的痕迹比如恶心的指针全局变量等等Pascal的改进版Object Pascal相对来说安全许多后来Borland干脆将Object Pascal换了个名字叫Delphi从此开创了一片面向对象编程的新世界 Delphi的严谨语法和快速编译吸引了众多的应用开发者加上Borland的完美的VCL组件体系比起MFC来方便而容易另外Delphi完整的数据库组件也将数据库开发变得简单而容易Delphi再次成为成熟的面向对象开发语言微软当然不会放过这些通过将MFC内置到操作系统中微软的VC++也抢回一些市场这也是为什么Delphi开发的应用程序编译后会比VCVB开发的程序大的原因

Sun的一个开发小组本来为了小型嵌入式系统开发OAK语言结果无心插柳柳成荫发展出了Java语言它是一个完全摆脱了传统语言的各种负担的面向对象的语言当然也保留了一些非面向对象的核心(原始类型)以保证速度现在Java也为最流行的面向对象语言之一当然微软同样不会放过它擅于模仿的微软立即弄出一个C#来与之竞争并在C#中保留了一些变种的指针(指代)以吸引传统的C开发者关于这些语言的各自特点这里就不一一赘述了

数据库与数据对象化

数据库是企业级应用不可缺少的因此在面向对象流行的时候数据库厂商也在进行着数据对象化的研究这些研究在上个世纪八十年代就初现端倪

数据库的对象化一般有两个方向一个是在主流的关系数据库的基础上加入对象化特征使之提供面向对象的服务但访问语言还是基于SQL另一个方向就是彻底抛弃关系数据库用全新的面向对象的概念来设计数据库这就是对象数据库ODBMS

关系数据库对象化SQL与JDBC

随着许多关系数据库厂商开始提供对象化服务各自的接口开始互不兼容在经历一些麻烦之后关系数据库厂商感觉到规范化的必要因为当初关系数据库雄霸天下时SQL标准起了很大作用大家可以按照统一的编程方式来访问高性能的商用数据库

关系数据库厂商集中起来重新将对象化服务规范起来形成了SQL规范将其中的对象结构等内容规范起来开始一个崭新的面向对象的关系数据库(ORDBMS)的历程

JDBC就是在这种情况下出台的它将对关系数据库中的对象服务的访问API规范起来为Java平台提供了访问ORDBMS的标准方式当然JDBC对传统的SQL操作也进行了很多功能增强

Oracle是一个传统的关系数据库厂商在对象化的道路上Oracle当然采取追加对象化特征的道路以侵入数据对象化的市场保持Oracle在数据库领域的领导地位如果说Oracle使Oracle走向全盛的话从Oracle开始Oracle就成为关系数据库加对象类型的先驱在Oracle我们可以定义一些数据结构(Record)将普通的类型包装在其中成为数据元素然后可以在客户端按Record结构进行访问初步提供了面向对象的数据库服务

对象数据库

对象数据库就是采用全新的面向对象概念来设计数据库的全新数据库类型在这方面主要以一些大学研究机构进行设计和开发有些也形成了产品不过由于市场方面的原因(主要是关系数据库的容易上手和市场绝对领导地位)和ODBMS先天的一些弱点(比如查询引擎很难优化)使ODBMS没有象关系数据库那样流行起来

不过对象数据库的对象化特点还是令人割捨不下目前还是有一些很好的产品在市场上从商用的到免费的都用目前在ODBMS领域占据领导地位的是VersantFastObjects和ObjectStore等几大厂商并且市场份额也在逐步扩展免费的产品包括C++编写的Ozone纯Java的dbo等等还有一些研究机构开发一些底层的面向对象数据库引擎但只提供一些底层的API不提供管理方面的功能以及一些算法提供开放式接口让厂商去选择和实现比如美国威斯康新大学计算机系数据库组的SHORE引擎就是一个非常出色的面向对象数据库引擎现在还在积极的更新中一些其它研究机构和数据库厂商采用它完成了自己的特别的对象数据库比如专用于地理信息的数据库专用于宇宙空间数据研究的数据库等等

目前对象数据库最大的障碍是缺乏统一的规范各个数据库厂商有各自的访问接口对象数据库比起关系数据库来不只是基本的几种数据类型那么简单它还涉及继承处理多态等一大堆面向对象特征的实现规范化道路当然困难重重这也是对象数据库无法普及的一个重要原因

也有一些机构提出了一些建议的规范比如制定Corba标准的OMG小组的一个分组ODMG提出的ODMG规范目前已经是版本其中的OQL对象查询语言相当具有吸引力还有一些中立的机构提出了其它的一些标准化的对象访问API也可算是面向对象数据库的规范之一象前面提到的FastObjects和Ozone就是符合ODMG规范的

Java对象映射

话说回来在一般的开发人员眼中数据库就是指关系数据库因此很多应用还是采用简单的JDBC来访问数据库在开发的过程中大家逐渐感觉到JDBC的局限性比如调用复杂容易产生资源洩漏等等与面向对象的Java语言有一段距离因此很多开发小组开始思考如何将应用中的数据进行对象化建模然后再想办法与JDBC结合起来这就是Java数据库开发中的层出不穷的对象包装技术

对象包装技术

传统包装与演变

传统包装顾名思义就是最初出现的包装方式很多公司都经历过这一步产生了很多风格各异的包装方法当然笔者也有过还算丰富的尝试过程

举例来说如果我们有一个用户类

public class User {

public int userId;

public String name;

public javautilDate birthday;

}

我们可以将其当作一个简单的数据类然后写一些工具方法来实现与JDBC的交互这些方法我们可以放到一个另外的工具类中也可以放到User类中作为静态方法这些方法包括简单的增查(以Oracle为例)

public class User {

public int userId;

public String name;

public javautilDate birthday;

public static User addUser(String name Date birthday) throws SQLException {

Connection conn = …; //获取一个JDBC连接

PreparedStatement ps = connprepareStatement(); // 获取一个序列值来作为用户标识

ResultSet rs = psexecuteQuery();

rsnext();

User user = new User();

useruserId = rsgetInt(); //读取序列值为新用户标识

username = name;

userbirthday = birthday;

ps = connprepareStatement(insert into …); //插入用户数据记录的SQL

pssetInt(userid);

pssetString(username);

pssetDate(userbirthday);

psexecuteUpdate();

rsclose();

psclose();

connclose();

return user;

}

public static void deleteUser(int userId) throws SQLException {

Connection conn = …;

//…

}

public static User getById(int userId) throws SQLException {

//…

}

//…

}

以上就是一个简单的数据包装的基本雏形我们可以看到这是一个非常简单的JDBC包装一些代码可以模块化以实现重用另外这段代码还有很大隐患就是中途如果出现异常的话就会使系统出现JDBC资源漏洞因为JDBC分配的资源(connpsrs等)是不能被Java虚拟机的垃圾回收机制回收的因此我们的addUser方法就需要改成下面的样子

public static User addUser(String name Date birthday) throws SQLException {

Connection conn = null;

PreparedStatement ps = null;

ResultSet rs = null;

User user = new User();

try {

conn = …; //获取一个JDBC连接

ps = connprepareStatement(); // 获取一个序列值来作为用户标识

rs = psexecuteQuery();

rsnext();

useruserId = rsgetInt(); //读取序列值为新用户标识

username = name;

userbirthday = birthday;

ps = connprepareStatement(insert into …); //插入用户数据记录的SQL

pssetInt(userid);

pssetString(username);

pssetDate(userbirthday);

psexecuteUpdate();

} finally {

//这里注意一定要按照创建的顺序关闭JDBC资源

if(rs != null) try { rsclose(); } catch(SQLException ex) { exprintStackTrace(); }

if(ps != null) try { psclose(); } catch(SQLException ex) { exprintStackTrace(); }

if(conn != null) try { connclose(); } catch(SQLException ex) { exprintStackTrace(); }

}

return user;

}

所有的数据库访问方法都必须进行这样的包装当我们的数据类达到一定的数量后(比如十几个几十个)这些方法占据了大量的代码维护困难出现BUG机会增多并且不易排错尤其是资源漏洞这种容易引起服务器稳定性问题的BUG

为了保持数据类的纯洁我们可以将JDBC操作方法集中到一个公共工具类中去完成这样这个工具类会非常庞大但每个数据类会变得很简单这种方式可以称作是DataAccessObject模式相当于EJB中的ValueObject是脱离数据库细节的纯对象模型

这些都是最基本的存储处理在基本增删改查(这里的查指按关键字查找对象)的基础上我们还需要进行复杂的匹配查询(SQL)这使得我们的存储处理代码进一步复杂化简单地我们可以写一个类似的方法

public static Collection findBy(String sql) throws SQLException {

//… (这里获取JDBC连接)

Collection col = new Vector();

ps = connprepareStatement(sql);

rs = psexecuteQuery();

while(rsnext()) {

User user = new User();

useruserId = rsgetInt();

username = rsgetString();

userbirthday = rsgetDate();

coladd(user);

}

return col;

//… (同前这里是清理JDBC资源的代码)

}

这就是一个查询接口的基本定义查询采用的语言仍是SQL

如果我们需要将参数从SQL串中独立出来以节省数据库的解析时间并规范化我们还需要将查询条件作为参数传递到这个方法中去方法的接口改为

public static Collection findBy(String sql Object[] params) throws SQLException {

//…

ps = connprepareStatement(sql);

for(int i = ; i < paramslength; i++) pssetObject(i+params[i]);

//…

}

调用的时候sql参数中会包含一些

select IDNAMEBIRTHDAY from USER where … = ? and … > ? and …

当然也有一些开发团队喜欢将所有可能的查询都写死成一个个的专用查询方法在其中完成对应的SQL操作这一点类似于EJBQL只不过是将EJBQL中容器实现的功能通过手工编码来实现这样做使得查询受到限制但可以提供更保险的接口

还有一些开发人员看到每个类中写这样一些查询方法使得这个类的代码变得庞大维护麻烦便将所有的查询方法放到一个公共的工具类中去只是在方法中再加入一个参数Class cls来表示需要查询哪个对象使得每个数据类变得紧凑一些当然这样的结果是那个公共类变得异常庞大谁维护谁倒霉可以说是牺牲一人幸福团队不过如果这个人心理素质不够好压力承受能力不强的话一些对数据类的改动可能会受到他的阻碍这时候就是一夫当关万夫莫开

现在我们已经实现了基本对象的包装现在才能开始考虑更多的问题首先我们可能会从规范化的角度出发给每一个属性加上读写访问器getter/setter在前面的User类中可能我们会将基本属性部分写为

public class User {

private int userId;

private String name;

private Date birthday;

//以下是针对以上属性的getter/setter一般可以用IDE工具生成

public int getUserId() { return userId; }

public void setUserId(int value) { userId = value; }

public String getName() { return name; }

public void setName(String value) { name = value; }

public Date getBirthday() { return birthday; }

public void setBirthday(Date value) { birthday = value};

//…

}

这样一个比较规范的数据类包装就算完成了

另外我们知道面向对象概念中一个属性可以是另一个对象也就是说对象之间是存在着引用关系的这种关系还分为一对一一对多多对多等几种情况从一个既定对象出发其某个属性可以是另一个对象也可以是包含另一组对象的集合那么在我们的数据包装里面当然最好也能方便地处理对象之间的关系假定现在我们又有一个数据类Group

public class Group {

public int grouId;

public String groupName

public Set users; //set of User

}

这里为了简单表明含义暂不采用getter/setter

而User对所属的Group有一个引用

public Group belongTo;

在这里UserbelongTo和Groupusers就是一个一对多的关系

在我们的数据类中如何才能实现数据库的存取呢?就算是不考虑Groupusers这个反向关系光是UserbelongTo就是一件头疼的事如果我们在取出一个User对象时同时将其Group对象也取出来可以保证不会在访问某个用户的组时得到一个null不过这样有几个缺点

数据类的存取处理(JDBC)变得复杂需要执行很多SQL读取才行有时候只需要访问User的基本属性时浪费时间和资源尤其是对集合型属性的预读取更加可怕

如果按这个逻辑双向的关系处理变得危险很容易陷入死循环如果要避免必须在类代码中加入一些特别的机制也是很麻烦的事

如果对象之间的关系是更复杂的情况下比如三个四个对象之间互相关联那就是一场噩梦对代码的编写和维护都异常艰难

于是很多开发人员自然而然地退后一步在User类中只保留一个groupId并不保存Group对象这样可以将UserbelongTo属性变成int类型而另外写一个getter方法

public Group getBelongTo() {

return GroupfindById(belongTo);

}

而在Group类中干脆将users属性去掉只保留一个方法

public Set getUsers() {

return new HashSet(UserfindBy(select … from USER where BELONG_TO=?new Object[]{ new Integer(groupId) }));

}

也许细心一点的读者已经看出来了这里的几个方法都没有将SQLException捕捉也没有在方法中声明也就是说是有语法错误的因为SQLException不是一个RuntimeException不错确实是这样不过我们这里为了简单明了起见省掉这些处理以更直接清楚地表达意思

这样实际上我们的对象关系包装已经名存实亡在类的内部有很多用于访问所引用对象的复杂代码这些已经违背了我们将对象关系保持的初衷有些开发人员甚至不在类中保留访问关系对象的方法而是在客户调用时再去访问另一对象类的读取方法

User user = UsergetById(…);

//对user对象进行一些访问如显示其姓名等等

Group group = GroupfindById(userbelongTo);

//对group对象进行一些访问如显示组名等等

在这样的代码里实际上我们已经从根本上退回了关系数据库的出发点这与直接访问数据表有多大区别呢?只不过是在表上面套了一层貌似面向对象的皮而已不幸的是这种方式还存在于很多应用之中

从前面提到的这些面向对象包装的细节问题我们可以看到这种传统包装方式的一些主要的缺陷

数据库命名与对象设计命名的一致性问题

很多时候我们兴致勃勃地设计好一个类图并且经过评审之后开始对它进行数据库包装这时候发现有些属性名在具体的数据库中与该数据库的关键字沖突不能用作表名或字段名必须在数据表设计时采用另外的名称或者很麻烦地加上引号来使用于是写数据库处理代码的人有意见了他必须很清楚地记得一个属性在类中是什么属性名在表中又是什么字段名在编写的类逐渐增多后尤其是一个类经过历次变动之后或者经过很长时间又需要改动并去处理这些JDBC代码时代码维护人员简单要发疯了!

对象的查询仍局限于SQL

这一点也是这种简单的包装方法最不能摆脱关系数据库的地方上面也已经说过一些命名沖突带来了很多维护工作量代码中必须还保留数据表的命名体系而不是对象类的命名体系这将使调用人员仍需要清楚记得两套命名体系无论时间经过多久或者开发人员是否有流动

此外对于普遍需要用到的连表查询也给应用开发带来困难这些地方仍不能突破SQL的限制

SQL资源占用多

在处理对象集合访问或者处理集合类型属性时往往我们只能在同一个Connection中处理一切事务这就要求一次性地将集合中的对象全部读入如果集合很大的话容易造成数据库拥塞使得性能大打折扣适得其反这方面的优化也是很多开发人员一直在努力改进的

对象关系处理复杂

前面提过对象之间的关系处理上普通的包装技术是一种表面上的处理在访问时调用者仍需要用大量的代码进行处理并且这还只是读取在写入关系属性时会有更多的细节问题需要处理

面向对象特色只能应用一小部分

面向对象的包装到前面所说的为止都还只是很基本的处理而面向对象的精华继承和多态在这里得不到任何帮助我们放弃了很多合理的设计来迁就数据库的包装

以上就是基本数据包装的主要缺陷还有更多的小问题也需要额外的处理

不过有责任心的开发人员当然不会就此善罢甘休他们冥思苦想可能会用更好的方式来实现对象之间关系的处理而且还会加入一些延迟访问的机制将对象之间的引用在需要用的时候才去连接数据库取数据另外在类的继承上他们也试图去在数据库包装上得到体现

值得感谢的是一些富有经验的团队在经历若干改进之后毫不吝惜将他们的成果贡献出来并将其独立化成为可复用的组件这也就是后来出现的对象包装产品包括商用的和免费的

产品化包装中间件

面向对象的包装产品化后逐步推广开来称作关系/对象映射O/R Mapping并且在产品化的过程中产品提供者在产品中逐渐提供了更多的功能先是一些自动命名转换器得以应用将客户代码中的类名属性名在内部处理的时候自动地转换到对应的数据库结构命名空间上这样应用开发的时候不再关心具体的数据库结构不再需要记忆不同地命名体系只需要一心一意地根据类图来进行开发在此之后这些O/R Mapping产品的开发团队又向前迈了一大步引入了词法分析器提供面向对象的查询语言!很多对象关系的查询使应用开发变得非常方便使O/R Mapping产品上了一个新的台阶

TopLink

TopLink是一个非常早期的产品最初面向C++后来也实现了Java的映射TopLink性能优异功能强大并且提供了独特的查询过滤器机制以及对关系的处理和查询都非常有效于是TopLink逐渐从商用化O/R Mapping产品中胜出成为市场上的最出色的映射产品也正因为这一点最大的关系数据库厂商Oracle将其收购成为提供最强数据库和最强对象映射中间件的厂商

CastorHibernate

TopLink虽然强大但太强大的东西免不了得意忘形TopLink开始将用户锁死到自己的产品上查询方式是最突出的它的查询体系含有很多别扭的概念(在我看来是如此)但为达到一般O/R产品不能达到的功能开发者只能接受这些慢慢地也产生积怨再加上其高昂的价格让很多新老用户望而却步于是免费的产品开始崛起

免费的O/R Mapping工具有很多种这里只提其中最有影响力的两种Castor和Hibernate

Castor是Exolab组织开发的面向Java的包装工具它最大的特色就是实现了大部分的ODMG OQL规范在查询上可以象完全使用一个对象数据库一样类图进行查询(后面会有介绍)它的原理是通过Java反射API去实现属性的设置和读取不过由于各种原因Castor后来的版本更新越来越慢最终停步在之前成为至今未出到正式版的O/R Mapping产品不管怎么样它还是一个相当不错的产品

Hibernate是一个现在很火热的O/R Mapping产品目前已经出到它功能一样强大同样使用Java反射API进行对象的设置但它的查询语言就是一套比较独特的体系这一点有点类似TopLink但Hibernate更具有亲和力对关系的查询更方便只不过比起Castor来在方便性和规范性上还是稍逊一筹就目前状况而言Hibernate的用户量和技术支持要强一些

面向对象的数据库查询

在对数据库进行面向对象研究的过程中软件世界的开发人员和设计人员们发现对数据库能够进行对象化的查询才是对数据库进行彻底的面向对象化这体现在我们使用一种全新的数据库查询语言能够很简洁易懂地对数据库中的对象进行查询一个典型的例子如下

假设我们已经有前面提到的两个数据类User和Group它们之间有一对多的关系UserbelongTo和Groupusers在数据库中已经存在很多这两个类的实例以及相互之间的关系我们可以使用下面的对象式查询语言来查询符合条件的User对象

select * from User where UserbelongToname=GROUP

或者

select userIdname from User where UserbelongToname=GROUP

等等从中我们可以看出通过使用面向对象中的成员属性指定符可以让我们达到SQL中的连表的效果实际上第一个句查询的SQL等价版本是

select a* from USER a GROUP b

where aBELONG_TO = bGROUP_ID

and bNAME = GROUP

由此可见对象式的查询语言比起实现同样功能的SQL语言来说简单了很多意义也更明确更符合使用者的思维习惯在类图比较复杂查询涉及的类又比较多的时候这种新型的查询语言体现出绝对的优势

ODMGOQLJava Binding

在面向对象式查询语言的研究过程中开发人员们逐渐实现了相似的查询语言然后互想取长补短最终在ODMG组织()的统一下形成了规范化的语言ODMG OQL这是一种完全面向对象的数据库查询语言语法与前面提到的类似不过考虑了更广泛的情况语句更加简洁而严谨

OQL并不是针对某种语言的它可以被应用到很多种开发语言中它不象SQL那样只是纯字符串式的查询语句因为面向对象查询中还必须提供相关类的信息所以OQL需要在编程语言中实现一些特定的API

目前ODMG的OQL已经被规范化地应用到SmallTalkJavaC++这些面向对象的程序设计语言当中在ODMG的规范中这几个模块被称作SmallTalk BindingJava Binding和C++ Binding

不过由于历史原因ODMG并没有象想象中地那样得到广泛应用现有的十几个面向对象数据库中采用ODMG OQL规范的少之又少目前也只有FastObjecctsOzone这些产品采纳了这个规范而象Versant这样的大厂商还没有采取OQL来查询数据库而是自己定义了自己的一套API称作VQL(Versant Query Lanaguage)

在JDO之前的O/R Mapping产品中也有一些产品使用OQL(有时候是其子集)比如CastorApache的Jakarta小组开发的OJB等等

第三方协议

软件世界是一个多姿多彩的世界总有那么一些好事之士不断地冒出新奇的想法还有一些开发面向对象数据库的组织制定了自己的一套对象式数据库查询语言自己的规范

不过这些规范相对来说影响力小得多比起ODMG来可以说应用范围太小更不用说与SQL这样广泛应用的标准进行比较了

EJBQL

Sun为了使Java应用在企业级数据库应用中不遗余力地推广JEE年的时候推出了EJB规范其中包含了富有特色的面向CMP方式的EntityBean的查询语言EJBQL功能类似于ODMG OQL只不过只能在EJB发布时静态地存在于应用描述符中不能在程序中动态地使用这是EJBQL最大的弱点也许EJB规范会将其动态化但到了那一天世界多半已经不是现在的样子了

JDO

JDO中有最近规定的一个对象式查询语言规范称作JDOQL比起OQL来JDOQL将查询语言中的很多元素与Java语言紧密地结合在一起有的人觉得麻烦有些人觉得规范评论各不相同从笔者个人的角度来看这样有利于没写过数据库应用没用过SQL的新手很快地习惯JDOQL但实际上有多少人会在没写过SQL没了解过关系数据库的情况下去用JDO写数据库应用呢?毕竟市场说明了一切个人认为JDO中对数据库对象的查询多少显得有些累赘如果能更简化一点那将更吸引使用传统SQL的开发人员

JDO历程与主要产品

说起JDO其来由还有一段特殊的背景Java语言在JDK达到比较实用的目的后企业级数据库应用也正是软件开发市场中的重要组成部分Sun看到这一点后也希望通过Java这个强大的武器在数据库开发市场攻占市场份额JDK推出后Sun同时推出了面向企业应用的EJB对基于java的中间件服务器框架进行了规范化定义这就是JEE不过在JDKJava的速度还是不能与传统的C/C++和Delphi这样一些应用开发语言相比为了防止业界对Java的激情因此而消退Sun宣布将在JDK中加入强大的虚拟机技术HotSpot其中包含更先进的垃圾收集算法和更优化的Java字节代码再编译技术(相当于JITJava即时编译技术)HotSpot引起了Java关注者的极大兴趣但Sun的HotSpot一拖再拖最后包含在JDK中出来时性能也没有象预期的那样好比起C++编译生成的代码来还是有一段距离

这个时候大家开始对Sun心存怀疑而Sun深知这一点于是将公众的注意力赶紧转移到EJB上从EJB到EJB再到EJB业界又开始关注JEE中间件技术上来很快开发人同发现用EJB来编写数据库应用还是有很大的难度虽然在分布式技术上EJB确实有很大的价值在这个时候Sun决定推出JDO技术作为轻量级的Java数据库访问规范而这一点也受到很多传统O/R Mapping市场的欢迎为了与传统O/R Mapping有所区别Sun一开始就高姿态地将JDO定位成不只是面向关系数据库的Java规范而是针对所有的存储技术包括面向对象数据库和其它类型的存储体系(如文件)就象EJB EntityBean一样虽然就笔者的角度这个做法使第一版的JDO抛弃了很多传统O/R Mapping提供的面向关系数据库的功能可以算是一个失策

规范提出JSR

JDO最早是由Sun召集众多的O/R Mapping开发团队集中起来共同提出的首先是通过会议确定了JDO需要包括的内容然后正式提出一个Java规范请求(JSR正式开始了JDO规范的制定下面是主要的进展里程碑

JSR # approved in July

组建的专家小组包括SunAppleBEAIBMOracleSAPWebGain等

完成公开评论草案

在JavaOne上引入

最终草案

最终草案公布

在JavaOne上启动

最终草案

版正式公布

修正版

规范启动

Oracle与JDO

作为JDO专家组的重要成员同时作为最大的关系数据库厂商的Oracle地位显然非同一般在JDO规范中Oracle也可说是立下汗马功劳很多API的形成Oracle都提供了很重要的参考意见最终的投票Oracle也是毫不犹豫

可是世间的事总是变化莫测的就在JDO快出台之时Oracle收购了TopLink这一点使Oracle的身份变得特殊而复杂TopLink是一个商业产品是以商业利益为目标的而Oracle也是追求利益最大化的典型商家这一点与JDO的开放精神背道而驰因此我们看到后期Oracle对JDO的不积极态度甚至在前一阵的JavaOne大会上有人从Oracle的角度非正式地攻击JDO

主要产品以及各自特点

在JDO规范制定的同时出现了几个主要的JDO产品有美国的基于对象数据库的FastObjects j法国的支持Versant对象数据库文件数据库主流RDBMS的LiDO南非的JDOGenie德国的JRelay等等这些都是很不错的JDO产品下面列举一下我对主要的几个产品的印象

LiDO(法国LibeLis公司)

我对JDO的认识主要是通过LiDO这个产品它在月的一份图文并茂的教程中简要解说了JDO的使用和优点这个教程可以在这里下载LiDO的特色是大而全支持文件型数据库RDBMSODBMS甚至是XML数据库不过配置较麻烦最新版本是RC

KodoJDO(美国Solarmetrics公司)

Kodo是JDO的中流砥柱之一在JDO还未最后通过的时候它就是一个比较成熟的产品了其特点是注重性能和稳定性目前最新版本是是客户最多的产品

JDOGenie(南非HemSphere公司)

这是目前我最推荐的产品最新版本是性能也不错稳定性还有待验证但它有一个最大的特点集成性好最易学其公司的CTO David Tinker也是一个善解人意的年轻人采纳了很多网友的意见对产品进行改进主要是在配置上非常方便有一个专门的图形界面工具可以进行配置数据库生成对象查询等等很实用的功能

JRelay(德国ObjectIndustries公司)

这也是一个出现得比较早的产品也有一个GUI工具用于配置曾几何时这个工具还是相对很方便的但一年多过去了好象没什么进展最新版本是我试过一段时间后来就没有再跟进了

FrontierSuite for JDO (美国ObjectFrontier)

这个产品与JRelayKodo一起可算是早期的JDO三个主要产品它支持正向开发和反向开发(Reverse Engineer)它的特色是反向工程(从表结构生成数据类)比较方便与UML的结合也很强不过真正运行起来的时候配置复杂

TJDO(一群跨国界的有志之士)

这是一个在Sun提供的参考产品(Reference Implementation)的基础上加入一些扩展功能而形成的一个免费产品目前最新版本是beta不过进展也缓慢这个版本已经出现好几个月了没有进一步的更新

目前状况与未来展望

月JDO规范正式公布以来各个产品层出不穷从商业到免费的层次都有不错的产品推出象KodoLidoJDOGenie等产品都已经比较成熟可以考虑投入开发使用JDO又推出修正版修正了版规范中的一些文字错误以及轻微地改进了部分异常定义不过改动都不大从现在的情形来看除了Kodo有一些大学的项目用到外好象还没看到多少使用JDO作开发的应用

JDO毕竟是一个新技术从概念上到实际应用上对其掌握的用户还不多而这些产品在配置使用上的方便性易用性还有待大幅度改进因此真正用JDO来开发项目的用户还廖廖无几至少我还不知道有哪些项目使用了JDO我自己也尝试使用JDO来开发项目但由于一些JDO版本中还不够完善的一些硬伤(比如不支持关系数据库统计功能)使我对JDO仍处于观望阶段

在八月中旬进行的JDO规划会议中来自各国的各个JDO产品厂商JDO技术咨询公司JDO研究机构的代表汇聚一堂将各自收集到的用户对JDO的需求总结起来提出一个个的新的议题并且确定了每个议题的JDO规范撰写负责人比如高级fetchGroup特性由目前实现得最好的JDOGenie的CTO David Tinker负责关于managedrelationship特性由Kodo的产品总监负责用户要求最多的JDO对象与PersistenceManager的脱钩/重挂钩特性由Sun的Craig Russell亲自操刀等等

最具有吸引力的JDO议题笔者个人认为是专门为关系数据库设立的子规范JDO/R这也是我一直以来最关心的这将使目前JDBC的开发将可以被JDO完全取代并且保证开发过程保持面向对象的特色还有一些将一个类映射到多个表之类的特性也在规范化的列表上这将有利于DBA在不影响应用开发的前提下根据需要更改数据表结构实现更好的性能类似的新特性还有很多粗略地看这些都规范化起来后真不知道各个厂商还能做什么样的扩展特性也许以后厂商之间拼的只能是技术支持服务和产品性能了当然最后还有价格的竞争

说了这么多我想大家关心的还是JDO到底什么时候能出来我们什么时候可以用上它什么时候有中文版产品价格到底如何这些问题目前笔者还无法一一回答只能根据笔者所掌握的信息初步解释一下据前几天的JDO启动大会上David Jordan的预期JDO正式版将在个月后正式完成那正式完成后厂商什么时候才能提供符合规范的产品呢?这个问题不用担心因为规范在制定的过程中会不断地公布公众预览版(Public Review)这样厂商可以先实现其中的功能等规范正式完成后也不会有太大的变化厂商也不会需要太多时间来跟进最终规范所以我估计一年之后我们就可以在JDO上进行开发了至于价格如何规范的产品初步印象是每个开发人员需要一个License一个License大概美元如果JDO产品的价格还保持这么贵的话(至少对中国用户来说)我们也还有很多免费(如JPOXTJDO)或半免费(如JCredo)产品可以选择最后一个关于中文版的问题有待于厂商对中国市场的考察或者看看是否有国内的JDO产品了不过在JDO规范制定的同时我们可以先集众人之力将其普及使广大的使用Java语言进行数据库开发的开发人员都来认识JDO了解JDO甚至将其用到项目开发之中

也许JDO的目标已经吸引了Java世界以外的人微软发现了这一点也立即计划在NET体系中加入一个仿照JDO的中间件具体是采用ObjectStore的产品ObjectStore是一个同时做JDO和NETDO(姑且使用这个名称)的公司

在这里笔者可以大胆地预测在未来的一两年内JDO将在Java世界大放光彩!

               

上一篇:Java图片预览功能实现

下一篇:研究Java的反编译性