[转载]如何用JDO开发数据库应用(3)

如何用JDO开发数据库应用(3)
4.3. 编辑metadata: system.jdo
这个过程,我们完全可以通过JDOGenie带的图形工具来完成。

我 们将上面两个类编译以后,打开JDOGenie的workBench,即运行JDOGenie1.4.7解包后的/workbench.bat,如果是在 Unix或Linux下就运行workbench.sh。注意要求你预先设置一个环境变量:JAVA_HOME,指向系统安装的JDK的根目录(不是 bin目录)。

我们在其中新建一个project(File--&gtNew Project),选择前面编译生成的类代码所在的根目录中(以下简称CLASSPATH,两个.class文件应该在该目录的credit system子目录中)存放这个project,因为这个project实际上是一个配置文件(注意不是.jdo文件),一般包含一些JDO产品相关的 信息,比如是否打开某些扩展功能,License号是多少等等,这个文件在运行时是需要的。我们选择一个project名:creditSys, JDOGenie会在CLASSPATH中将这个project保存为一个名为“creditSys.jdogenie”的文件。

我们先设置数据库,为保证实用性,我们选择MySQL作为底层数据库,安装MySQL的过程很简单,从MySQL网站下载4.0.13版本,安装到系统中,然后启动mysql服务即可。我们会采用其安装后自动生成的“test”数据库作为本文的数据库。

我们还需要在MySQL网站上下载jdbc驱动:版本号是3.0.7,下载后,将其ZIP包中的mysql.jar文件解出来放到某个目录中备用。

设置数据库的界面如下:


screen.width-333)this.width=screen.width-333;" src="http://www.java-cn.com/technology/tech_images/1972_004.jpg" alt="按此在新窗口浏览图片" />

配置好数据库后,可以点击下面的“Test”按钮测试一下连接是否正常。可能你会看到一个找不到MySQL的JDBC驱动的错误提示,没关系,我们直接点击OK,进入project属性配置界面,在其中将JDBC驱动加入,然后再回来测试连接即可。

project属性配置界面基本上不需要怎么设置,只要做两个必须的配置:

将MySQL的JDBC驱动加入到CLASSPATH中
将我们的类代码的根目录加入到CLASSPATH中
界面如下:


screen.width-333)this.width=screen.width-333;" src="http://www.java-cn.com/technology/tech_images/1972_005.jpg" alt="按此在新窗口浏览图片" />

点 击“OK”后,我们就到了主窗口,在主窗口中,我们可以进行metadata的编辑工作。我们通过菜单Meta--&gtAdd Classes将前面的两个数据类加入到元数据中,表示这两个类是需要存储的。其余的数据表结构等等繁琐的事务,我们全部留给JDOGenie自动完成。 添加数据类的过程中需要创建一个元数据文件,根据JDO的标准,一般情况下我们只需要在CLASSPATH根目录下创建一个“system.jdo”即 可。加入数据类后的界面如下:


screen.width-333)this.width=screen.width-333;" src="http://www.java-cn.com/technology/tech_images/1972_006.jpg" alt="按此在新窗口浏览图片" />

而自动生成的元数据文件system.jdo内容非常简单,实际上直接用手工写也不难:

<?xml version="1.0" encoding="UTF-8"?>







不过如果类比较多,之间关系也比较复杂的时候,就最好通过工具完成,以免出现语法和语义错误,除非你已经很有经验。

之 后,我们选择菜单的Build--&gtRecreate Schema来创建相应的数据库。数据库的表结构是自动生成的,如果你对其中一些表名或字段名或字段长度有异议,可以在主窗口中自定义。这里为简明扼要, 全部采用自动生成。如果你想在建表之前看看数据结构,可以选择菜单“Build--&gtView Schema”先预览一下生成的表结构SQL代码:

-- credit.system.CreditCard
create table credit_card (
credit_card_id INTEGER not null, --
address VARCHAR(255), -- address
allow_over_draft FLOAT, -- allowOverDraft
balance FLOAT, -- balance
create_time DATETIME, -- createTime
idcard VARCHAR(255), -- idcard
initial_balance FLOAT, -- initialBalance
last_transaction_time DATETIME, -- lastTransactionTime
nme VARCHAR(255), -- name
phone VARCHAR(255), -- phone
jdo_version SMALLINT not null, --
constraint pk_credit_card primary key (credit_card_id)
) TYPE = InnoDB;

-- za.co.hemtech.jdo.server.jdbc.sql.HighLowJdbcKeyGenerator
create table jdo_keygen (
table_name VARCHAR(64) not null,
last_used_id INTEGER not null,
constraint pk_jdo_keygen primary key (table_name)
) TYPE = InnoDB;

-- credit.system.TransactionRecord
create table transaction_record (
transaction_record_id INTEGER not null, --
amount FLOAT, -- amount
credit_card_id INTEGER, -- card
create_time DATETIME, -- createTime
note VARCHAR(255), -- note
jdo_version SMALLINT not null, --
constraint pk_transaction_record primary key (transaction_record_id)
) TYPE = InnoDB;


接 下来,我们保存这个Project,也就是将配置信息写入“creditSys.jdogenie”。下面我们就可以继续开发了,也就是说,我们所有的数 据类包装工作就全部完成了,已经可以享受JDO的自动维护的对象存储和灵活的面向对象的JDOQL查询语言的好处了。

JDOGenie1.4.7还有一个好处,是它新增的UML类图功能,简洁明了地给出数据类之间的关系,对于理解别人的数据模型非常有用。选择菜单“Meta--&gtDiagrams”,将所有的类都加到图中,即可看到本文中的数据模型:


screen.width-333)this.width=screen.width-333;" src="http://www.java-cn.com/technology/tech_images/1972_007.jpg" alt="按此在新窗口浏览图片" />
如果类比较多的话,可能这些关系线段会有交叉,那就需要我们手动地调整一下各个类的位置,做到尽量减少交叉。一个复杂一点的类图示范如下(未调整位置):


screen.width-333)this.width=screen.width-333;" src="http://www.java-cn.com/technology/tech_images/1972_008.jpg" alt="按此在新窗口浏览图片" />
4.4. 增强我们的数据对象类代码
配置信息写完了,metadata也生成好了,下面就是用JDOGenie的类代码增强器增强我们编译生成的类代码。在这里,由于需要配置一些CLASSPATH、JDO文件路径等,我们写了一段Ant脚本来完成这些麻烦的工作。

这个Ant脚本保存在我们的项目根目录下,名为“build.xml”:

<?xml version="1.0" encoding="GB2312" ?>





























这样,我们需要增强类代码的时候,在DOS框中,在 build.xml所在的目录下运行“ant”,即可完成增强过程。另外,要运行测试程序类credit.system.Main的话(后面会讲到),只 需要运行“ant run”即可,这样可以解决没有类似JBuilder的IDE的问题。


4.5. 编写业务逻辑方法:永远不能回避的任务
业务逻辑,好象在面向对象编程中常常提到,但到底什么是业务逻辑呢?难道仅仅是为了显示自己很高深,所以张口闭口就业务逻辑?确实有这样一些人,谈论开发的分析与设计时,脱口而出就是“业务逻辑”,实际上可能他们自己也不知道到底什么才是业务逻辑。

我 个人的理解可能也不是很充分。我是这样理解的:在应用中与存储无关的对象之间的协作(即属性的关联性的变化)就是业务逻辑,一般体现为一些规则,比如:当 新生成一个交易时,就将信用卡的总交易次数加1,将系统的总交易次数也加1。类似这样的规则就是业务逻辑,这些是每个应用特定的,是工具无法自动为你实现 的,必须在你自己的应用代码中体现,不论是作为Java代码,还是作为数据库存储过程,总之,必须有一段代码来体现这些业务逻辑。

采 用JDO解决了存储的问题之后,我们就可以编写工具类(独立于数据类的包含业务逻辑方法的类)来完成需求中描述的功能了。注意我们在下面的代码中用到的 JDO API。具体API的使用参见JDO文档以及本文末的参考文章中的《Java Data Objects第一章翻译》。

在完成第一个功能需求之前,我们先建立一些基础代码以将JDO集成起来。我们写一个名为“credit.system.Main”的工具类(也可称为控制类),来提供这些基础的方法:

package credit.system;

import javax.jdo.*;
import java.util.*;

public class Main {

public static void main(String[] args) throws Exception {
System.out.println("开始测试功能……");
}

/**
* 本方法专用于获取JDO API的核心对象:存储管理器PersistenceManager
*/
public static PersistenceManager getPersistenceManager() {
if(pmf == null) {
java.util.Properties p = new java.util.Properties();
try {
//从配置文件读入配置信息
p.load(Main.class.getClassLoader().getResourceAsStream("/creditSys.jdogenie"));

} catch(IOException ex) {
throw new RuntimeException(ex);
}
pmf = JDOHelper.getPersistenceManagerFactory(p);
}

return pmf.getPersistenceManager();
}
private static PersistenceManagerFactory pmf;
}

为 能让我们的代码能够编译并运行,我们还需要JDO的API包和JDOGenie的支持包,这些支持包都被合成到JDOGenie的lib目录下的 “jdogenie.jar”文件中,还有一个JTA包也是JDOGenie运行时必须的,即其lib目录下的jta.jar。我们将这两个jar文件拷 贝到我们的项目目录下,以便与JDOGenie的目录划清界限,另外,还需要将JDOGenie的license目录下的 “jdogenie.license”文件(也就是通过邮件获取的license文件),放到我们的CLASSPATH中。当然,也可以将该 license文件和JTA包一并压缩到jdogenie.jar中,我就喜欢这样做,这样可以使对JDOGenie的依赖浓缩到一个jar文件中,方便 在不同JDO产品间切换(因为我一般会让一个应用在不同的JDO产品下工作,以保证规范性和兼容性)。

4.5.1. 录入信用卡资料
为了放置业务逻辑方法,为简便起见,我们将在Main类中用静态方法来完成这些业务功能。首先,我们写一个方法来完成添加信用卡资料的功能:

/**
* 录入新信用卡,只需要录入必须的资料,其它的信息自动产生。
* @return 生成的新信用卡对象
* @throws IdCardDuplicatedException 身份证号重复,不允许创建新卡
*/
public static CreditCard inputCard(
String name,
String address,
String idcard,
String phone,
float initialBalance,
float allowOverDraft
) throws IdCardDuplicatedException {

CreditCard cc = new CreditCard();
cc.setName(name);
cc.setAddress(address);
cc.setIdcard(idcard);
cc.setPhone(phone);
cc.setInitialBalance(initialBalance);
cc.setAllowOverDraft(allowOverDraft);

//以下是自动产生的信息:
cc.setCreateTime(new Date());
cc.setBalance(initialBalance); //使刚创建后的余额等于初始余额,这是典型的业务逻辑

//下面将新信用卡保存到数据库,注意其中的JDO API。
PersistenceManager pm = getPersistenceManager();
//先检测是否已经有该身份证注册的信用卡存在:
Query q = pm.newQuery(CreditCard.class,"idcard==_newIdcard");
q.declareParameters("String _newIdcard");
Collection existCards = (Collection)q.execute(idcard);
if(existCards.iterator().hasNext()) {
throw new IdCardDuplicatedException(); //已经该身份证号存在
}

//身份证号没重复,以下保存该信用卡对象:
pm.currentTransaction().begin(); //每次对数据库的更新必须放到事务中
pm.makePersistent(cc);
pm.currentTransaction().commit(); //提交新对象
pm.close(); //释放JDO资源

return cc;
}

public static class IdCardDuplicatedException extends RuntimeException {}


下面我们运行一下这个程序,将Main.main()改写如下:

public static void main(String[] args) throws Exception {
System.out.println("开始测试功能……");

inputCard("张三","东风东路311号","223003433995431237","020-38864157",500.00f,5000.0f);
System.out.println("信用卡已创建!");
}

编译,并运行(也可以在build.xml所在目录下运行“ant run”),系统显示:

开始测试功能……
jdbc.con.connect jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=GB2312
jdbc.stat.exec set session transaction isolation level read committed
jdbc.stat.execQuery select version()
jdbc.con.rollback
jdbc.con.close
jdbc.con.connect jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=GB2312
jdbc.stat.exec set session transaction isolation level read committed
jdbc.stat.execUpdate update jdo_keygen set last_used_id = last_used_id + ? where table_name = ´transaction_record´
jdbc.stat.execQuery select max(transaction_record_id) from transaction_record
jdbc.stat.exec insert into jdo_keygen (table_name, last_used_id) values (´transaction_record´, 0)
jdbc.con.commit
jdbc.stat.execUpdate update jdo_keygen set last_used_id = last_used_id + ? where table_name = ´credit_card´
jdbc.stat.execQuery select max(credit_card_id) from credit_card
jdbc.stat.exec insert into jdo_keygen (table_name, last_used_id) values (´credit_card´, 0)
jdbc.con.commit
jdbc.con.commit
jdbc.con.rollback
JDO Genie: Created RMI registry on port 2388
JDO Genie: Bound to jdogenie.jdogenie1
pm.created
jdoql.compile credit.system.CreditCard
idcard==_newIdcard
jdbc.stat.execQuery select credit_card_id, address, allow_over_draft, balance, create_time, idcard, initial_balance, last_transaction_time, nme, phone, jdo_version from credit_card where idcard = ?
jdbc.con.commit
tx.begin
tx.commit
jdbc.con.connect jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=GB2312
jdbc.stat.exec set session transaction isolation level read committed
jdbc.stat.execUpdate update jdo_keygen set last_used_id = last_used_id + ? where table_name = ´credit_card´
jdbc.stat.execQuery select last_used_id from jdo_keygen where table_name = ´credit_card´
jdbc.con.commit
jdbc.stat.exec insert into credit_card (credit_card_id, address, allow_over_draft, balance, create_time, idcard, initial_balance, last_transaction_time, nme, phone, jdo_version) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
jdbc.con.commit
jdbc.con.commit
pm.closed
信用卡已创建!


以 上信息说明我们的第一个功能已经正常完成,一条信用卡记录已经生成到数据库中。你可以通过mysql的数据库查询工具验证。我们发现Main函数返回后, 系统并未退出运行,为什么呢?原来JDOGenie在默认的状态下打开了远程控制的监听服务,这对以后跟踪WebApp的服务器状态并进行调节时是很有用 的。不过在这里只会干扰我们的视线,姑且将它关掉:在JDOGenie的工作台中,选择“File--&gtProject Properties”菜单,然后在弹出的项目属性配置对话框中将“Remote Access”检查框清掉,表示禁止远程访问,然后点击“OK”,并保存该Project。

然后,我们再次运行credit.system.Main,这次我们看到两个现象:一是程序扔出了异常,表示身份证号重复,这符合我们的预期;二是系统退出了,没有产生监听的线程,这即是刚才更改配置的结果。

到 此为止,我们的创建信用卡的功能便完成了,现在我们来看一看JDOGenie提供的工作台集成的JDOQL查询功能:在工作台(WorkBench)中选 中CreditCard类,然后选择菜单“Run--&gtView Class Extent”可以查看CreditCard类的所有对象,这里我们看到下面的结果:



screen.width-333)this.width=screen.width-333;" src="http://www.java-cn.com/technology/tech_images/1972_009.jpg" alt="按此在新窗口浏览图片" />
如果我们修改程序并创建了多张信用卡的话,在这个对话框中会看到更多的CreditCard类的实例对象(上图实际上已经显示了两张信用卡信息。

下面我们接着实现需求描述中的其它功能,并且在输出信息中不再显示JDOGenie的调试跟踪信息(实际上在项目配置中可以将这些信息屏蔽掉),如图(将日志级别改为“errors”):


screen.width-333)this.width=screen.width-333;" src="http://www.java-cn.com/technology/tech_images/1972_010.jpg" alt="按此在新窗口浏览图片" />
4.5.2. 浏览信用卡信息
这个功能仅仅是一个对所有信用卡的查看。实际上前面已经看到,在工作台中已经可以很轻松地完成这个功能,不过我们这里需要在程序中完成。

我们在Main类中加入一个方法:listCards()

/**
* 列出系统中所有的信用卡资料
*/
public static void listCards() {
PersistenceManager pm = getPersistenceManager();
for(Iterator itr = pm.getExtent(CreditCard.class,false).iterator();
itr.hasNext(); ) {
Object o = itr.next(); System.out.println("DataStoreIdentity="+JDOHelper.getObjectId(o)+", "+o); }
pm.close(); }


该 方法列出当前系统中的所有信用卡,包括自动生成的卡号(对象标识)。可以看到,方法的内容非常简单。你可以不屑一顾地说:哦,原来JDOGenie的工作 台中的查看类对象的功能也不过如此而已!不错,确实如此而已,原因很简单:科技以人为本,JDO的目标就是简化操作!

另外,再将main()方法改一下:

public static void main(String[] args) throws Exception {
System.out.println("开始测试功能……");

listCards();
}


然后编译,运行,结果如下(如果用Ant来运行,可能显示结果会有一些Ant工具的信息,以后不再解释):

开始测试功能……
DataStoreIdentity=1979371451-1, 信用卡:余额=500.0,持卡人=张三,身份证号=223003433995431237,电话=020-38864157
DataStoreIdentity=1979371451-11, 信用卡:余额=500.0,持卡人=李四,身份证号=320012194501032339,电话=020-38864157


这 里,我们可以看到几点:一是JDOGenie的日志功能已经关闭(前面的设置生效了),二是显示信用卡时利用到了CreditCard中的 toString()方法。俗话说,机遇只照顾有准备的头脑,前面我们似乎是画蛇添足地给两个数据类加入了toString()方法,现在我们看到,这两 个方法发挥了作用!

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/374079/viewspace-132080/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/374079/viewspace-132080/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值