如何用JDO开发数据库应用(3)

发表于:2007-07-14来源:作者:点击数: 标签:
如何用JDO 开发 数据库 应用(3) · 3. 我们要做什么-- 需求 描述 本节主要描述本文中将要做的应用程序的功能。这个应用程序非常简单,是基于一位网友提出的一个《 银行 信用卡交易系统》中提取出来的一个功能子集,并作了一定的简化和功能改动,以便能体
如何用JDO开发数据库应用(3)

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

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

录入信用卡资料。
信用卡资料包括以下信息:
卡号(自动生成)
持卡人姓名
身份证号
地址
联系电话
开户日期(自动生成)
开户金额
目前余额(自动计算)
允许透支额

浏览信用卡信息
浏览当前所有的信用卡资料
交易刷卡
针对信用卡产生一次交易,需要录入以下信息:
卡号、交易额
如果超出透支额,则提示无法完成交易。
如果交易成功,系统自动记录交易时间
存款
录入卡号和存款额
查询透支报表
查看当前所有透支的信用卡
查询交易明细
可根据持卡人身份证号查询所有的交易信息
以上就是整个应用的功能,非常简单,如果采用JDBC,我们立即会想到先建两个表:信用卡表和交易表,二者通过卡号关联,然后这些功能就是一堆SQL和这两个表组合而成的大杂烩。然而,我们现在要采用JDO来做,怎么做呢?请继续往下看……

· 4. 开发过程

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

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

先编写原始的数据对象模型代码并编译成为.class文件,这些数据对象称作原始对象(POJO,Plain Old Java Objects)
然后编写存储描述符Metadata,也称元数据,表明一些与存储相关的设置,比如哪些类需要保存到数据库,每个类中的哪些字段需要优先读入,哪些字段延迟读入(LazyLoad)等等,这个metadata必须放到CLASSPATH中,扩展名是“.jdo”。
metadata的编写一般可以通过工具来完成,比如JDOGenie的工作台(WorkBench)就可以轻松地完成。

写完描述符后,就采用某个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对开发的帮助有哪些》一文。

在上面的信用卡类中,我们认为信用卡号只是对信用卡的一个标识,不参与业务逻辑,所以我们采用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属性即可得到。这也是面向对象的便捷性之一。

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

(未完待续)

原文转自:http://www.ltesting.net