用JDOGenie进行基于JDO的项目开发向导

来源:互联网 发布:登陆微博显示网络出错 编辑:程序博客网 时间:2024/05/20 09:07
<script type="text/javascript"><!--google_ad_client = "pub-2947489232296736";/* 728x15, 创建于 08-4-23MSDN */google_ad_slot = "3624277373";google_ad_width = 728;google_ad_height = 15;//--></script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
<script type="text/javascript"><!--google_ad_client = "pub-2947489232296736";/* 160x600, 创建于 08-4-23MSDN */google_ad_slot = "4367022601";google_ad_width = 160;google_ad_height = 600;//--></script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>

如何用JDO开发数据库应用

(本文的版权属作者本人,欢迎转载,但必须注明出处和原作者)

本文将介绍如何使用Sun公司的最新《Java Data Objects 》规范来进行基于数据库的简单应用程序的开发,从而使读者对JDO有一个直接的感性的认识,为更深入的开发作铺垫,同时也希望抛砖引玉,让更多的富有经验的高手也参与到推广JDO的进程中来,为读者提供更多更精彩的文章!

1. JDO是何方神圣,难道是ADO的翻版?

本节对稍熟悉JDO一点的读者来说,可能算是老生常谈,一堆垃圾,不如回收掉算了。不过我却认为这些是实话实说,有感而发,不吐不快,对新手可能也有一定的帮助,至少应该有一点共鸣吧。所以,老手请直接跳过本节。

1.1. Java的优点

自从Java语言面世以来,它那几乎完全面向对象的特性和解放我们程序员的自动垃圾回收机制给我们展现了一个全新的开发天地:原来程序还可以这样写!我用过几年C++,里面的指针简直折寿!我还记得有些功能里面不得不使用类似“***lpszInfoMapOfMap”之类的变量,它是指针的指针的指针,要在编码过程中准确地把握这一点已属不易,何况还要记得释放每一处占用的内存,并且还不能释放多次(严格地说,应该是将自己申请的内存进行且只进行一次释放)!我至今都还很佩服当年清晰的头脑,然而在调试过程层出不穷的“AccessViolation”和“NullPointer”错误竟使我一夜白头!(有一次熬夜调试一个问题,第二天憔悴了很多。)C++之后,我也用过三年以上的Delphi,程序代码好理解、易维护了很多,不过指针仍是胸中永远的痛!直到Java,才使我脱离苦海,进入“按思维的速度进行开发”的时代……

当Java的速度得到很大改善后,我们开始用它来写数据库应用,但说实话,Java的数据库方面还很原始,图形界面编程中的数据库组件很不好用,再加上主要写的是Web应用,只有JDBC接口可供选择。提起JDBC,我相信很多读者都会有这样的印象:概念太多,严密但麻烦,尤其是资源的释放也是一大问题。比起微软的ADO来,简直是一团乱麻,容错性尤其差劲。

1.2. 对象包装技术,百家争鸣?群魔乱舞?

于是,从规范化开发的原则出发,我们开始写自己的JavaBean来包装数据对象,使数据对象化,避免太多的地方涉及JDBC操作。但一些问题也随之而来:灵活性不够,接口死板,性能低下,这使我一阵苦恼。于是,“君子性非异也,善假于物也”,咱也上网去找点“技术支持”!很快,竟然被我发现了“Castor JDO”,一个专用于数据包装的撞阕榧峁┝薕DMG标准的OQL作为查询语言,方便且容易理解,比SQL好多了。这让我享受了一段时间的“面向对象的数据库开发”的好处,一句话,“效果不错,还实惠!”。

然而,好景不长,Castor一些内在的BUG影响了稳定性,而这个免费产品的更新又太慢,一直未能解决。只好放弃。“执手相看泪眼,竟无语凝噎”!怎么办?要知道,由俭入奢易,由奢入俭难,吃过肉的人,怎能忍受只能吃菜的生活!象《甲方乙方》里面那个一心想吃素的大款还是不多见的。对我们来说,再使用JDBC原始调用似乎难以下咽,再用JavaBean包装又有点返古,于是我又开始了网上的搜寻历程。余秋雨先生有《文化苦旅》,咱这也算是《编程苦旅》了,呵呵,苦笑。

从网上的资料来看,我的这些经历也是很多Java开发同仁的共同经历,无论是国内还是国外,不过从实际情况来看,国外的研究更深入更广泛一些,至少从网上所能找到的资料来说是这样。美国从八十年代起就开始研究面向对象的数据库ODBMS,目前已有一些成形的产品,比如Versant公司的Versant数据库,FastObjects公司的FastObjects t7数据库,以及其它一些相对市场份额小一些的诸如ObjectStore等公司的产品,当然,也不乏一些免费的产品,如Orient等等。总的来说,ODBMS尽管拥有面向对象的优点,但由于历史原因,在与关系数据库RDBMS的竞争中始终处于下风,基于RDBMS的应用还是占绝大多数,因此,出现了Object-Relational映射的一些工具,前面提到的Castor就是近年来出现的一个工具,实际上更早的时候,已经有一些成熟、稳定的商业化产品出现,比如前一阵被Oracle收购的TopLink,被BEA收购的WebGain等等,比较有名气的CocoBase等等。

象TopLink这样的产品我也了解了一下,功能确实强大,性能、稳定性都有优势,然而,其同样强大的价格和古怪的API令我却步。我很担心被锁定在某个产品上面,无法脱身,众所周知,Java给我们的就是一种自由的感觉,自由,永远是那么地吸引人。

出路在哪里?JDO浮现在我眼前。

1.3. JDO浮出水面,可别以为是ADO

JDO自1999年起就由一些经常写数据库对象映射层的富有经验的开发人员提出大纲,他们在长期的面向对象开发中进行了大量的数据库方面的处理和对象化包装,终于,多种多样的包装方式引起很多兼容性方面的问题。于是,一些主要的开发团队就联合起来,以SUN为领头羊,制定了JDO规范。它的目标不是取代JDBC或EJB,而是在JDBC的基础上进行包装,同时又可以做EJB的底层(CMP),简化J2EE服务器提供商的工作。JDO主要面向中小型规模的项目,不过随着产品提供商(Vendors)给出越来越多的功能(Feature),比如分布式的同步控制等等,JDO的作用也越来越大。
JDO规范在Sun的富有经验的Craig Russel的带领下,经过三年的讨论,终于在2002年四月形成了第一版。目前最新版是1.0.1版,在 http://access1.sun.com/JDO/ 可以看到。
(大家应该知道,Java的规范形成时间一般都比较长,因为它太开放了,任何人都可以发表意见,参与制定规范的人都要考虑这些意见)

ADO是微软的数据访问组件集合,相信很多写过基于ASP页面的数据库应用的朋友都印象深刻,快速、容错性强是它的特点,不过扩展性就不敢恭维,写多少年都是那几个东东,无法超越。一些刚接触JDO的读者可能会将JDO与ADO搞混起来,以为是Java版的ADO,那就大错特错了,两者风马牛不相及,可以说不是一个档次上的东西。庆幸的是,微软没有将“xDO”这类缩写注册成商标或专利,否则两个大块头又要打官司了,嘿嘿,我倒是喜欢看热闹,打起来同样精彩!

1.4. JDO产品介绍

JDO规范自从2002年4月推出以来,出现了很多种各有特色的产品,当然,这些产品都遵循JDO规范,不会影响你写的JDO应用的可移植性。下面列举一下我对各个产品的印象:(参见第6节的JDO开发数据库应用.htm#reference_articles">参考文章:《JDO资源介绍》)

    1. 教父:LiDO(法国LibeLis公司)
      我对JDO的认识主要是通过LiDO这个产品,它在2002年3月的一份图文并茂的教程中简要解说了JDO的使用和优点。这个教程可以在这里下载:JDO.pdf">http://www.objectweb.org/conference/JDO.pdf。LiDO的特色是大而全,支持文件型数据库、RDBMS、ODBMS,甚至是XML数据库。不过配置较麻烦。最新版本是2.0RC。
    2. 霸主:KodoJDO(美国SolarMetrics公司)
      Kodo是JDO的中流砥柱之一,在JDO1.0还未最后通过的时候,它就是一个比较成熟的产品了,其特点是注重性能和稳定性,目前最新版本是2.5.0,是客户最多的产品。
    3. 最佳传教士:JDOGenie(南非HemSphere公司)
      这是目前我最推荐的产品,最新版本是1.4.7,性能也不错,稳定性还有待验证,但它有一个最大的特点:集成性好,最易学,其公司的CTO David Tinker也是一个善解人意的年轻人,采纳了很多网友的意见对产品进行改进,主要是在配置上非常方便,有一个专门的图形界面工具,可以进行配置、数据库生成、对象查询等等很实用的功能。强烈推荐!
    4. 大家闰秀:JRelay(德国ObjectIndustries公司)
      这也是一个出现得比较早的产品,也有一个GUI工具用于配置,曾几何时,这个工具还是相对很方便的,但一年多过去了,好象没什么进展,最新版本是2.0,我试过一段时间,后来就没有再跟进了。
    5. 两面派:JDO/">FrontierSuite for JDO (美国ObjectFrontier)
      这个产品与JRelay、Kodo一起,可算是早期的JDO三剑客,称它为两面派是因为它正向开发和反向开发都还可以。它的特色是反向工程(从表结构生成数据类)比较方便,与UML的结合也很强,不过真正运行起来的时候,配置复杂。当初该公司曾许诺我以10%的价格买一份,可惜我当时没在意。如果上天再给我一次机会……
    6. 免费午餐:JDO">TJDO(一群跨国界的有志之士)
      这是一个在Sun提供的参考产品(Reference Implementation)的基础上加入一些扩展功能而形成的一个免费产品,目前最新版本是2.0beta3,不过进展也缓慢,这个版本已经出现好几个月了没有进一步的更新。

     

以上这些是我用过的比较有代表性的产品,还有很多商业产品,以及其它一些或规范或不完全规范的免费JDO产品(如XORM、OJB等),这里不再一一列举,有兴趣的读者可以到JDOcentral.com/"> http://www.JDOcentral.com/ 去进一步了解。

2. JDOGenie是哪路英雄

前面已经提过,JDOGenie是南非的一个商业化产品,可别小看南非人,他们的收入可不少!当然技术也不错。如果读者做过UML的建模和设计,可能会知道Together Control Center这个产品,也就是最近被Borland收购的一个UML设计工具。JDOGenie的出品公司HemSphere就是Together的南非总代理和合作伙伴。

说到这里,插句题外话,IBM收购了Rational,Borland收购了Together,Sun收购了DescribeUML,一场IDE+UML的大战又将上演。

好,书归正传,JDOGenie是我目前最推荐的产品,原因是易学易用,简单上手,对于想学习JDO的朋友是最适合不过的了!它有一个图形界面的配置工具,可在里面进行数据表映射、SQL操作、JDOQL查询等等功能,非常方便。对采用JDOGenie的Web服务器也可以通过这个图形工具进行监控,可以了解哪些查询费时,哪些查询执行次数多等等,有助于数据库优化调节。

俗话说,百闻不如一见,下面先给几张图片,过把瘾先:

控制台界面(WorkBench):

 

以下的内容是以JDOGenie为底层来介绍JDO的开发流程的,所以需要先下载JDOGenie:

先到JDO/download.html">http://www.hemtech.co.za/JDO/download.html下载最新版本(本文使用的是1.4.7),然后点击该页面上的“Obtain Evaluation License”链接获取一个月的试用License(一个月会不会太少了?放心,该公司在快到期时会发布一个新的License的)。在获取试用License的时候需要填写一些资料。

3. 我们要做什么--需求描述

本节主要描述本文中将要做的应用程序的功能。这个应用程序非常简单,是基于一位网友提出的一个《银行信用卡交易系统》中提取出来的一个功能子集,并作了一定的简化和功能改动,以便能体现JDO的特点,主要完成以下功能:

    1. 录入信用卡资料。
      信用卡资料包括以下信息:
      • 卡号(自动生成)
      • 持卡人姓名
      • 身份证号
      • 地址
      • 联系电话
      • 开户日期(自动生成)
      • 开户金额
      • 目前余额(自动计算)
      • 允许透支额
    2. 浏览信用卡信息
      浏览当前所有的信用卡资料
    3. 交易刷卡
      针对信用卡产生一次交易,需要录入以下信息:
      卡号、交易额
      如果超出透支额,则提示无法完成交易。
      如果交易成功,系统自动记录交易时间
    4. 存款
      录入卡号和存款额
    5. 查询透支报表
      查看当前所有透支的信用卡
    6. 查询交易明细
      可根据持卡人身份证号查询所有的交易信息

    以上就是整个应用的功能,非常简单,如果采用JDBC,我们立即会想到先建两个表:信用卡表和交易表,二者通过卡号关联,然后这些功能就是一堆SQL和这两个表组合而成的大杂烩。然而,我们现在要采用JDO来做,怎么做呢?请继续往下看……

4. 开发过程

刚才看上面这一段功能需求的功夫,JDOGenie也应该down下来了,如果还没有的话,感紧安装一个ADSL吧!(别乱猜,我可不是电信的职工!咱只有羡慕的份……)。

采用JDO进行开发的过程大致如下:

  1. 先编写原始的数据对象模型代码并编译成为.class文件,这些数据对象称作原始对象(POJO,Plain Old Java Objects)
  2. 然后编写存储描述符Metadata,也称元数据,表明一些与存储相关的设置,比如哪些类需要保存到数据库,每个类中的哪些字段需要优先读入,哪些字段延迟读入(LazyLoad)等等,这个metadata必须放到CLASSPATH中,扩展名是“.JDO”。
    metadata的编写一般可以通过工具来完成,比如JDOGenie的工作台(WorkBench)就可以轻松地完成。
  3. 写完描述符后,就采用某个JDO产品的增强器(Enhancer)来根据元数据的描述改造编译生成的.class文件,使这些类代码JDO化,然后就可以在其它代码中调用了。应用代码中主要通过JDO存储管理器(javax.JDO.PersistenceManager,以后简称PM)来完成对数据对象的增加、删除、修改、查询等操作。

示意图如下(摘自Versant公司的JDO教程):其中的XML Config即是指*.JDO

4.1. 如何建模

当我们将自己的头脑OO化之后,以上的需求在我们头脑里变成了几个基本的对象:信用卡和交易记录,以及对这些对象进行的一些操作。(其实我们的头脑本来就是基本客观世界的对象的,应该说本来就是OO的,要不然大脑怎么会是一些环成“O”状的肠子呢?:D)

为简单明了,我们这里的建模也不采用类似ROSE或Together这样的大型的UML工具了。在Duke或Quake中,有时候步枪,甚至是电锯,会成为最有效最直接的杀人工具,而CS里面手枪也往往出奇制胜。现在,在程序开发的战场上,我们祭出最原始的利器:记事本!相信没有一个人不会使用它。简单点说,我们下面的内容都直接以源代码作为建模的说明。

首先,我们分析信用卡这个类,很简单,将前面列出的字段作为属性加到类中即可,这和建表的过程其实差不了多少(只是碰到对象之间的关系时,思路会有不同)。

package credit.system;import java.util.Date;public class CreditCard {    String name; //姓名    String address; //地址    String idcard; //身份证号    String phone; //电话    Date createTime; //开户日期    Date lastTransactionTime; //最近一次交易的日期    float initialBalance; //开户金额    float balance; //目前余额    float allowOverDraft; //允许透支额}

咦,好象有什么地方不对劲?不错,你的眼光真犀利!“我搞了这么多年数据库应用开发,从没见过没有关键字的表,也没见过这样一个没有标识字段的类!卡号哪儿去了??!!”

是啊,卡号哪儿去了?没有卡号的信用卡谁敢用?趁早卷铺盖回家吧!

别急,这里先给大家介绍一下JDO的一个关于对象标识的概念:标识实际上只是一个对象的唯一标记,有点象一个对象的内存地址,对传统的数据库来说,就是一条记录的主键。JDO认为,如果关键字只是用于标记一个对象的唯一性,而不参与业务逻辑(比如计算),则不必将它放到类代码中,这种唯一性的维护只需要由JDO中间件(Implementation)去完成,这种对象标识叫做Datastore Identity,一般实现上是使用递增整数;如果标识也参与业务逻辑(如主键是创建时间,会用于排序或范围查找),则可以在类代码中出现,这种对象标识叫做Application Identity。关于这些概念,请参考本文尾部JDO开发数据库应用.htm#reference_articles">参考文章中的《JDO对开发的帮助有哪些》一文。

在上面的信用卡类中,我们认为信用卡号只是对信用卡的一个标识,不参与业务逻辑,所以我们采用Datastore Identity的方式,让标识的唯一性由JDO产品去维护,就象对象在内存中的地址不需要我们在程序代码中指定,而是由JVM去维护一样。

咦,好象又有什么地方不对劲?不错,你的眼光还是这么犀利!“你的信用卡没有标识,那我的交易记录怎么去关联它??!!”

对啊,以前我写的JavaBean包装的数据对象,也需要有一个主键属性,另一个对象通过一个同样类型的属性来与这个对象关联,现在你这个主键属性都没了,我怎么去关联呢?无的放矢?

这个问题问得很好,也非常典型(注意,是非常典型,不是“非典型”)。

不过问这个问题的人,应该都是写过多年数据库应用的富有经验的开发人员,数据表、主键、外键关联的意识已经深入头脑,就算变成Java类,主键外键还是阴魂不散。这种方式可谓“换汤不换药”,没什么实质的变化,这样的对象模型也不能体现出对象之间的关系,只能通过程序员自己去把握。说实话,我最初也是这样去做对象包装的,惭愧惭愧,现在让我们步子再大一点,观念再开放一点,看看JDO中的概念吧:对象之间如果有关系的话,只需要直接将关系到的对象声明为一个该类型的属性(或属性集合)即可。

这样,我们的交易记录类就写成了下面的样子:

package credit.system;import java.util.Date;public class TransactionRecord {    Date createTime; //交易发生时间    float amount; //交易金额    String note; //备注    CreditCard card; //信用卡}

在这个类中,我们看到里面没有一个“信用卡号”的属性,取而代之的是一个信用卡对象“card”,这样,我们就不会需要在通过交易记录取得相关信用卡的时候去调用一条查询语句来取得信用卡对象了,只需要简单地读取这个交易记录对象的card属性即可得到。这也是面向对象的便捷性之一。

有了这两个类,我们的《银行信用卡交易系统》的基础也就搭起来了。

4.2. 如果怕出乱子……建议的代码规范

记得以前听过一句话,“世间永恒不变的真理就是不存在永恒不变的真理”,这里,我也想说一句:编程世界里最完美的解决方案就是不要认为有最完美的解决方案。(说什么啊,简单听不懂。呵呵,我自己也有点听不懂)。

我想说的是:JDO也是有一定的限制的,不能让你完全地展开双翅(注意,是“鱼翅”),在面向对象的大海中遨游。为什么JDO会有限制呢?因为它的原理是将你的类代码进行一定的改造,将JDO涉及的一些管理和维护代码插入到类代码中,这样,你的调用代码可能需要进行一些改变。这些就是JDO的限制。简单地说,如果你得到了一个TransactionRecord类型的对象tr,想通过它取得涉及的信用卡对象,不建议通过下面的代码:tr.card得到,而是建议将这个属性声明为private的,然后给出一个getter来获取(getCard()),也就是进行JavaBean式的属性包装。这样,我们的两个数据类就会变成下面的样子:

CreditCard.java:package credit.system;import java.util.Date;public class CreditCard {    String name; //姓名    String address; //地址    String idcard; //身份证号    String phone; //电话    Date createTime; //开户日期    Date lastTransactionTime; //最近一次交易的时间    float initialBalance; //开户金额    float balance; //目前余额    float allowOverDraft; //允许透支额<script type="text/javascript"><!--google_ad_client = "pub-2947489232296736";/* 728x15, 创建于 08-4-23MSDN */google_ad_slot = "3624277373";google_ad_width = 728;google_ad_height = 15;//--></script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
<script type="text/javascript"><!--google_ad_client = "pub-2947489232296736";/* 160x600, 创建于 08-4-23MSDN */google_ad_slot = "4367022601";google_ad_width = 160;google_ad_height = 600;//--></script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>