📄 如何用jdo开发数据库应用.htm
字号:
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; //允许透支额
}
</PRE>
<P>咦,好象有什么地方不对劲?不错,你的眼光真犀利!“我搞了这么多年数据库应用开发,从没见过没有关键字的表,也没见过这样一个没有标识字段的类!卡号哪儿去了??!!”
</P>
<P>是啊,卡号哪儿去了?没有卡号的信用卡谁敢用?趁早卷铺盖回家吧!</P>
<P>别急,这里先给大家介绍一下JDO的一个关于对象标识的概念:标识实际上只是一个对象的唯一标记,有点象一个对象的内存地址,对传统的数据库来说,就是一条记录的主键。JDO认为,如果关键字只是用于标记一个对象的唯一性,而不参与业务逻辑(比如计算),则不必将它放到类代码中,这种唯一性的维护只需要由JDO中间件(Implementation)去完成,这种对象标识叫做Datastore
Identity,一般实现上是使用递增整数;如果标识也参与业务逻辑(如主键是创建时间,会用于排序或范围查找),则可以在类代码中出现,这种对象标识叫做Application
Identity。关于这些概念,请参考本文尾部<A
href="file:///C:/temp/如何用JDO开发数据库应用.htm#reference_articles">参考文章</A>中的《JDO对开发的帮助有哪些》一文。</P>
<P>在上面的信用卡类中,我们认为信用卡号只是对信用卡的一个标识,不参与业务逻辑,所以我们采用Datastore
Identity的方式,让标识的唯一性由JDO产品去维护,就象对象在内存中的地址不需要我们在程序代码中指定,而是由JVM去维护一样。</P>
<P>咦,好象又有什么地方不对劲?不错,你的眼光还是这么犀利!“你的信用卡没有标识,那我的交易记录怎么去关联它??!!”</P>
<P>对啊,以前我写的JavaBean包装的数据对象,也需要有一个主键属性,另一个对象通过一个同样类型的属性来与这个对象关联,现在你这个主键属性都没了,我怎么去关联呢?无的放矢?</P>
<P>这个问题问得很好,也非常典型(注意,是非常典型,不是“非典型”)。</P>
<P>不过问这个问题的人,应该都是写过多年数据库应用的富有经验的开发人员,数据表、主键、外键关联的意识已经深入头脑,就算变成Java类,主键外键还是阴魂不散。这种方式可谓“换汤不换药”,没什么实质的变化,这样的对象模型也不能体现出对象之间的关系,只能通过程序员自己去把握。说实话,我最初也是这样去做对象包装的,惭愧惭愧,现在让我们步子再大一点,观念再开放一点,看看JDO中的概念吧:对象之间如果有关系的话,只需要直接将关系到的对象声明为一个该类型的属性(或属性集合)即可。</P>
<P>这样,我们的交易记录类就写成了下面的样子:</P><PRE>package credit.system;
import java.util.Date;
public class TransactionRecord {
Date createTime; //交易发生时间
float amount; //交易金额
String note; //备注
CreditCard card; //信用卡
}
</PRE>
<P>在这个类中,我们看到里面没有一个“信用卡号”的属性,取而代之的是一个信用卡对象“card”,这样,我们就不会需要在通过交易记录取得相关信用卡的时候去调用一条查询语句来取得信用卡对象了,只需要简单地读取这个交易记录对象的card属性即可得到。这也是面向对象的便捷性之一。</P>
<P>有了这两个类,我们的《银行信用卡交易系统》的基础也就搭起来了。</P>
<H3>4.2. 如果怕出乱子……建议的代码规范</H3>
<P>记得以前听过一句话,“世间永恒不变的真理就是不存在永恒不变的真理”,这里,我也想说一句:编程世界里最完美的解决方案就是不要认为有最完美的解决方案。(说什么啊,简单听不懂。呵呵,我自己也有点听不懂)。</P>
<P>我想说的是:JDO也是有一定的限制的,不能让你完全地展开双翅(注意,是“鱼翅”),在面向对象的大海中遨游。为什么JDO会有限制呢?因为它的原理是将你的类代码进行一定的改造,将JDO涉及的一些管理和维护代码插入到类代码中,这样,你的调用代码可能需要进行一些改变。这些就是JDO的限制。简单地说,如果你得到了一个TransactionRecord类型的对象tr,想通过它取得涉及的信用卡对象,不建议通过下面的代码:tr.card得到,而是建议将这个属性声明为private的,然后给出一个getter来获取(getCard()),也就是进行JavaBean式的属性包装。这样,我们的两个数据类就会变成下面的样子:</P><PRE>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; //允许透支额
public String toString() {<BR> return "信用卡:余额="+balance+",持卡人="+name+",身份证号="+idcard+",电话="+phone;<BR> }</PRE><PRE> public void setName(String value) { name = value; }
public String getName() { return name; }
public void setAddress(String value) { address = value; }
public String getAddress() { return address; }
public void setIdcard(String value) { idcard = value; }
public String getIdcard() { return idcard; }
public void setPhone(String value) { phone = value; }
public String getPhone() { return phone; }
public void setCreateTime(Date value) { createTime = value; }
public Date getCreateTime() { return createTime; }
public void setLastTransactionTime(Date value) { lastTransactionTime = value; }
public Date getLastTransactionTime() { return lastTransactionTime; }
public void setInitialBalance(float value) { initialBalance = value; }
public float getInitialBalance() { return initialBalance; }
public void setBalance(float value) { balance = value; }
public float getBalance() { return balance; }
public void setAllowOverDraft(float value) { allowOverDraft = value; }
public float getAllowOverDraft() { return allowOverDraft; }
}
TransactionRecord.java:
package credit.system;
import java.util.Date;
public class TransactionRecord {
Date createTime; //交易发生时间
float amount; //交易金额
String note; //备注
CreditCard card; //信用卡
public String toString() {<BR> return "交易记录:持卡人="+card.name+",身份证号="+card.idcard
+",交易额="+amount+",时间="+createTime;<BR> }</PRE><PRE> public void setCreateTime(Date value) { createTime = value; }
public Date getCreateTime() { return createTime; }
public void setAmount(float value) { amount = value; }
public float getAmount() { return amount; }
public void setNote(String value) { note = value; }
public String getNote() { return note; }
public void setCard(CreditCard value) { card = value; }
public CreditCard getCard() { return card; }
}
</PRE>
<P>实际上,这些增加getter和setter的过程有很多工具可以帮忙,比如JBuilder,或者是Together,甚至是最小而精的免费工具<A
href="http://gexperts.com/">Gel</A>!</P>
<P>这样的采用访问器包装私有属性的建议,一般来说绝大多数Java开发人员都还是可以接受的。</P>
<H3>4.3. 编辑metadata: system.jdo</H3>
<P>这个过程,我们完全可以通过JDOGenie带的图形工具来完成。</P>
<P>我们将上面两个类编译以后,打开JDOGenie的workBench,即运行JDOGenie1.4.7解包后的/workbench.bat,如果是在Unix或Linux下就运行workbench.sh。注意要求你预先设置一个环境变量:JAVA_HOME,指向系统安装的JDK的根目录(不是bin目录)。</P>
<P>我们在其中新建一个project(File-->New
Project),选择前面编译生成的类代码所在的根目录中(以下简称CLASSPATH,两个.class文件应该在该目录的credit\system\子目录中)存放这个project,因为这个project实际上是一个配置文件(注意不是.jdo文件),一般包含一些JDO产品相关的信息,比如是否打开某些扩展功能,License号是多少等等,这个文件在运行时是需要的。我们选择一个project名:creditSys,JDOGenie会在CLASSPATH中将这个project保存为一个名为“creditSys.jdogenie”的文件。</P>
<P>我们先设置数据库,为保证实用性,我们选择MySQL作为底层数据库,安装MySQL的过程很简单,从<A
href="http://www.mysql.com/">MySQL网站</A>下载4.0.13版本,安装到系统中,然后启动mysql服务即可。我们会采用其安装后自动生成的“test”数据库作为本文的数据库。</P>
<P>我们还需要在MySQL网站上下载jdbc驱动:版本号是3.0.7,下载后,将其ZIP包中的mysql.jar文件解出来放到某个目录中备用。</P>
<P>设置数据库的界面如下:</P>
<P><IMG height=477 src="如何用JDO开发数据库应用.files/CSDN_Dev_Image_2003-7-21253156.jpg"
width=594></P>
<P>配置好数据库后,可以点击下面的“Test”按钮测试一下连接是否正常。可能你会看到一个找不到MySQL的JDBC驱动的错误提示,没关系,我们直接点击OK,进入project属性配置界面,在其中将JDBC驱动加入,然后再回来测试连接即可。</P>
<P>project属性配置界面基本上不需要怎么设置,只要做两个必须的配置:</P>
<OL>
<LI>将MySQL的JDBC驱动加入到CLASSPATH中
<LI>将我们的类代码的根目录加入到CLASSPATH中 </LI></OL>
<P>界面如下:</P>
<P><IMG height=433 src="如何用JDO开发数据库应用.files/CSDN_Dev_Image_2003-7-21253158.jpg"
width=554></P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -