用 Apache Derby 进行开发取得节节胜利 用 Apache Derby 进行 Java 数据库开发第 6 部分.docx
《用 Apache Derby 进行开发取得节节胜利 用 Apache Derby 进行 Java 数据库开发第 6 部分.docx》由会员分享,可在线阅读,更多相关《用 Apache Derby 进行开发取得节节胜利 用 Apache Derby 进行 Java 数据库开发第 6 部分.docx(15页珍藏版)》请在冰豆网上搜索。
用ApacheDerby进行开发取得节节胜利用ApacheDerby进行Java数据库开发第6部分
简介:
了解如何构建一个自包含(self-contained)、可部署的嵌入式ApacheDerby数据库应用程序。
本文是本系列的最后一篇文章,您将把数据库表映射到Java™类中,编写DataAccessObject(DAO)并将它们与业务逻辑类一同集成到完成的数据库应用程序中。
您还将了解如何把应用程序与必要的Derby数据库文件打包在一起,创建一个包含数据库应用程序所有必要内容的压缩文件。
开发嵌入式ApacheDerby应用程序
回想在本系列的文章中,您一直在使用ApacheDerby数据库。
Derby数据库支持两种交互模式:
网络模式和嵌入模式。
较为熟悉的交互模式可能是网络模式,在这种模式下,数据库服务器运行在一台计算机上,并且数据库客户机通过网络连接连接到中央服务器上。
这种设置描述了大多数商业数据库的安装设置,通常都是遵循事务处理模型。
关于ApacheDerby和Java的更多信息:
∙使用Derby创建wiki系统,第2部分:
Java函数、过程和触发器
∙利用Stripes、ApacheDerby和Eclipse进行无配置的J2EE开发
∙将任意数据持久存储到ApacheDerby中
∙关于IBMCloudscape的更多信息
另一个模型是嵌入模式,在这种模式下,应用程序不但包含实现必要业务逻辑的软件,而且包含数据库引擎软件。
最终,应用程序可以完全自包含,有助于简化安装和设置过程。
为了强调这一点,因此考虑在本系列的所有文章中,始终只以嵌入模式使用ApacheDerby数据库。
现在就要开始开发您自己的嵌入式Derby数据库应用程序。
开发嵌入式数据库应用程序的过程一般可以分为三个步骤:
1.将数据库逻辑映射到Java类中。
2.开发管理数据库专有功能的Java代码。
3.实现Java应用程序中的业务逻辑。
这一节的其余部分先详细讨论这三个步骤,然后再继续讨论如何部署嵌入式ApacheDerby应用程序。
对象-关系映射
本系列中的前几篇文章已经通过使用虚构的Bigdog的SurfShop业务介绍了数据库概念。
这个简单的数据库将管理冲浪器材店的存货,主要关注包含冲浪器材店产品的数据库表。
在本文中,您将开发一个显示冲浪器材店存货中具体项目详细清单的应用程序。
对象-关系映射软件
在本文中,您将显式构造Java代码,从而将关系数据库数据映射到Java类中。
假定这个问题会给大型软件项目增加一定的复杂度,自动执行此过程可以减少发生软件错误的可能性。
若干个商业和开源软件产品可以与ApacheDerby数据库结合使用以自动执行此过程。
您可以在本文的参考资料部分中找到这些产品的完整清单链接。
需要处理的第一步是实现映射到产品的Java类,该产品是bigdog.products表中的一行。
在执行此操作时,您会遇到一个问题:
表模式是在SQL中定义的,然而业务应用程序是用Java语言定义的。
在SQL关系数据模型与Java对象模型之间映射有时会带来挑战,尤其是对于涉及通过主键-外键连接许多表的复杂数据库模式(或Java对象模型)。
在形式上,此过程被称为对象-关系映射(Object-RelationalMapping,ORM)。
但是,对于这个演示应用程序,您将面对的惟一复杂度是如何把bigdog.products表的模式中使用的SQL数据库类型映射到适当的Java数据类型中。
在本例中,过程相对简单,如清单1所示,在该清单中将定义Product类。
清单1.将产品表映射到JavaProduct类
publicclassProduct{
privateintitemNumber=0;
privateBigDecimalprice=null;
privateDatestockDate=null;
privateStringdescription=null;
publicProduct(intitemNumber,BigDecimalprice,DatestockDate,Stringdescription){
this.itemNumber=itemNumber;
this.price=price;
this.stockDate=stockDate;
this.description=description;
}
publicvoidprintProduct(){
Stringline="------------------------------------";
System.out.println("\nBigdog'sSurfShopProductInformation");
System.out.println(line+line);
System.out.printf("ItemNumber:
%-11s\n",this.itemNumber);
System.out.printf("ItemPrice:
$%-8.2f\n",this.price);
System.out.printf("ItemStockDate:
%-10s\n",this.stockDate);
System.out.printf("ItemDescription:
%-40s\n",this.description);
System.out.println(line+line+"\n");
}
...
由于本系列的第十篇文章中从bigdog.products表中提取数据时介绍了关于执行查询的课程,因此您应对这个清单中提供的映射有些熟悉。
该类定义了将bigdog.products表中的列与适当的Java数据类型相匹配的属性。
在实践中,您可以为每个属性添加完整的getter/setter方法,虽然在这段演示代码中并没有这样做,但是大多数流行开发环境通常都会自动完成此操作。
Product类中的两个主要方法是根据需要初始化对象的构造函数,以及为特定产品生成格式良好的输出的printProduct方法。
此方法将被演示应用程序调用,但是放置在此类中以利用紧密耦合的优点——毕竟,谁能比定义类更了解输出对象的方法?
通常,您要为必须向业务应用程序公开的数据库中的每张表定义Java类。
因此,虽然这样做对于这个简单的演示并不必要,但是您也可以构造一个Java类映射到bigdog.vendors表。
封装数据库逻辑
在数据库表被成功地映射到Java类中后,下一步是把数据库表与相应的Java类连接起来。
一种可能的做法是将这段连接代码直接放到相应的Java类中——例如,清单1中提供的Product类。
但是,在大多数情况下,这样做不好,因为这将在数据库与数据库应用程序之间引入紧密连接。
就像您在本系列中被反复警告的那样,通常应当尽量避免使用紧密耦合。
更好的方法是实现一个接口层,在该层中可以封装特定于数据库的Java代码。
在这种方法中,如果数据库详细保存了更改,例如位置、版本甚至基本模式修改,则应用程序将被隔离;您需要做的惟一更改仅限于更改DAO。
此中间层中的Java类被称为DAO,并且连接到数据库表的每个Java类通常都有一个DAO类。
例如,在清单2中,ProductDAO类提供了先前定义的Product类的DAO。
清单2.把产品表中的行链接到JavaProduct类
SELECTitemNumber,price,stockDate,description"+
"FROMbigdog.productsWHEREitemNumber=?
";
...
publicProductgetProduct(inttargetItemNumber){
Productproduct=null;
try{
pstmt.clearParameters();
pstmt.setInt(1,targetItemNumber);
ResultSetrs=pstmt.executeQuery();
if(rs.next()){
intitemNumber=rs.getInt("itemNumber");
BigDecimalprice=rs.getBigDecimal("price");
DatestockDate=rs.getDate("stockDate");
Stringdescription=rs.getString("description");
product=newProduct(itemNumber,price,stockDate,description);
}
rs.close();
}catch(SQLExceptionse){
printSQLException(se);
}
returnproduct;
}
...
ProductDAO类的主要用途是创建一个由bigdog.products表的特定行中的数据组成的新Product对象。
该行是由传入getProduct方法中的targetItemNumber值识别的。
虽然它没有显示在清单2中,但是此类还将通过发出SELECTMAX(itemNumber)FROMbigdog.products查询并分析查询结果,确定最大项目数(演示应用程序需要)。
如果查看清单2,您可以轻松地看到底层数据库模式与DAO类之间的紧密耦合。
在getProduct方法中,将通过执行PreparedStatement提取数据。
通过添加附加层,最大限度地降低任何数据库更改所产生的影响——对于微小更改,此演示应用程序中惟一需要更新的类是ProductDAO。
您还可以把数据库管理代码放到一个单独的类中以封装这类功能,如清单3所示。
清单3.数据库管理代码
publicclassDBManager{
privatestaticConnectioncon=null;
privatestaticfinalStringdriver="org.apache.derby.jdbc.EmbeddedDriver";
privatestaticfinalStringurl="jdbc:
derby:
";
privatestaticfinalStringdbName="SurfShop";
...
privateProductDAOpdao=null;
publicDBManager(){
if(!
dbExists()){
try{
Class.forName(driver);
con=DriverManager.getConnection(url+dbName+";create=true");
processStatement(createProductsSQL);
con.setAutoCommit(false);
batchInsertData(insertProductsSQL);
mit();
}catch(BatchUpdateExceptionbue){
...
}
}
pdao=newProductDAO(con);
}
publicvoidclose(){
try{
con=DriverManager.getConnection(url+";shutdown=true");
}catch(SQLExceptionse){
;//DoNothing.Systemhasshutdown.
}
con=null;
}
publicProductDAOgetProductDAO(){
returnpdao;
}
privateBooleandbExists(){
Booleanexists=false;
try{
Class.forName(driver);
con=DriverManager.getConnection(url+dbName);
exists=true;
}catch(Exceptione){
;//Donothing,asDBdoesnot(yet)exist
}
return(exists);
}
...
清单3中提供的DBManager类是此应用程序中最大的类。
有一部分原因是因为演示应用程序比较简单,但是它也反映了从Java应用程序中与数据库进行成功交互的复杂度。
此类负责管理数据库连接,包括建立初始连接和创建演示应用程序要访问的ProductDAO实例。
由于这是嵌入式应用程序,因此这段代码还负责创建和初始化嵌入式数据库本身。
在这个类中,您将通过使用dbExists方法完成此操作,该方法将尝试建立数据库连接。
如果数据库不存在,将抛出一个异常,并且DBManager构造函数自己将创建数据库。
然后它将创建bigdog.products表,并且最后通过一次批插入操作插入10个新行。
遵循这个逻辑,如果该应用程序被执行第二次,则dbExists方法将成功连接(假定不知何故并未删除本地存储的数据库),并跳过数据库创建过程。
为了简化各种数据库连接操作,JDBCURL被编码为jdbc:
derby,并且根据所需的操作附加不同的后缀。
例如,url+dbName+";create=true"用于创建数据库,而url+dbName用于建立数据库连接。
关于DBManager类的最后一个要点是提供close方法。
此方法将通过尝试用附加在基本JDBCURL中的数据库属性shutdown=true建立数据库连接,显式关闭ApacheDerby嵌入式数据库。
通过这种方式关闭数据库,可以保证所有事务都将被正常关闭。
这将使得数据库可以更加快速地重新启动,因为数据库将一直处于前后一致状态。
开发嵌入式应用程序
过程的最后一个正式步骤是开发Java应用程序。
为了保持简单,此演示应用程序:
∙在命令行中接受来自用户的数字输入
∙检索拥有输入项目号的产品信息
∙显示用户要查看的产品
给定先前定义的类,演示应用程序代码相对简短并且易于实现,如清单4所示。
清单4.嵌入式ApacheDerby应用程序代码
importjava.io.BufferedReader;
importjava.io.InputStreamReader;
publicclassDemoApp{
privateDBManagerdbm=null;
privateProductDAOpdao=null;
privateintmaxItemNumber=0;
publicDemoApp(){
this.dbm=newDBManager();
this.pdao=dbm.getProductDAO();
this.maxItemNumber=pdao.getMaxItemNumber();
}
publicvoidshowProduct(){
intitemNumber=0;
Productp=null;
BufferedReadercin=newBufferedReader(newInputStreamReader(System.in));
while(true){
try{
System.out.print("Enterobjectitemnumber(0toExit):
");
itemNumber=Integer.parseInt(cin.readLine());
}catch(Exceptionex){
;//Donothing.Inthissimpledemoyouignoreanyinputerrors.
}
if(itemNumber==0)
break;
elseif((itemNumber<0)||(itemNumber>this.maxItemNumber))
System.out.println("Invalidproductitemnumber,pleasetryagain.");
else{
p=pdao.getProduct(itemNumber);
p.printProduct();
}
}
dbm.close();
}
publicstaticvoidmain(String[]args){
DemoAppda=newDemoApp();
da.showProduct();
}
}
清单4中所示的应用逻辑包含在这个类的两个方法中:
构造函数和showProduct方法。
构造函数将按照前面的描述创建一个DBManager对象以建立数据库连接,然后获得ProductDAO类的实例。
此实例将在showProduct方法中使用,用于从数据库中检索必要的数据。
构造函数还将从数据库检索最大项目数,这将简化错误管理。
showProduct方法将从控制台的标准输入流中读取一个整数。
如果该整数值是bigdog.products表的允许值,则将通过使用bigdog.products表中的相应数据创建Product对象,并且使用printProduct方法显示该值。
此过程将一直持续,直到用户输入零以终止循环为止。
回页首
部署嵌入式ApacheDerby应用程序
在成功地实现并测试嵌入式ApacheDerby数据库应用程序之后,下一步是把所有必要的文件打包在一起,以便您可以根据需要部署应用程序。
这一节的其余部分将指导您完成先前构造的演示应用程序的打包过程。
第一步(如果尚未这样做)是将可从下载部分获得的样例代码文件解压缩,如清单5所示。
清单5.准备构建嵌入式ApacheDerby应用程序
rb$mkdirderbyWork
rb$cdderbyWork/
rb$unzip../derby14.zip
Archive:
../derby14.zip
inflating:
DBManager.java
inflating:
DemoApp.java
inflating:
Product.java
inflating:
ProductDAO.java
inflating:
manifest.txt
rb$moremanifest.txt
Main-Class:
DemoApp
Class-Path:
lib/derby.jar
rb$
如您所见,第一步是创建一个新的工作目录,然后把样例代码文件解压缩到这个新目录中。
压缩样例代码文件包括五个文件:
演示应用程序的四个Java源代码文件和manifest.txt文件,其中的内容如清单5所示,由包含名称-值对的两行组成。
您将使用这个manifest文件为演示应用程序构建可执行的JAR文件。
第一个名称-值对将指定主要应用程序驱动程序的类的名称,本例中为DemoApp。
第二个名称-值对将指定查找ApacheDerby数据库Java类的位置,这些嵌入模式下的类全都包含在derby.jar文件中。
下一步是把必要的文件一起打包到.jar文件中,如清单6所示。
清单6.构建嵌入式ApacheDerby应用程序
rb$mkdirlib
rb$cp$DERBY_INSTALL/lib/derby.jarlib/
rb$javac*.java
rb$jarcvmfmanifest.txtdemoapp.jar*.class
addedmanifest
adding:
DBManager.class(in=5087)(out=2792)(deflated45%)
adding:
DemoApp.class(in=1460)(out=881)(deflated39%)
adding:
Product.class(in=1684)(out=919)(deflated45%)
adding:
ProductDAO.class(in=2625)(out=1369)(deflated47%)
rb$ls
DBManager.classProduct.classdemoapp.jar
DBManager.javaProduct.javalib
DemoApp.classProductDAO.classmanifest.txt
DemoApp.javaProductDAO.java
rb$rm-rf*.java*.classmanifest.txt
rb$ls
demoapp.jarlib
rb$zipdemoapp.zipdemoapp.jarlib/derby.jar
adding:
demoapp.jar(deflated6%)
adding:
lib/derby.jar(deflated8%)
rb$rm-rfdemoapp.jarlib
rb$ls
demoapp.zip
交付ApacheDerby软件
虽然ApacheDerby数据库是开源软件产品,但是有许可要求。
幸运的是,嵌入式应用程序只有一个要求:
您必须将ApacheDerby2.0版许可副本(有关链接,请参阅参考资料)连同包括任何ApacheDerby数据库软件的任何软件产品一起交付。
该过程的第一步是根据manifest文件中所示的CLASS-PATH:
lib/derby.jar名称-值对的要求,创建lib目录,然后把derby.jar文件复制到这个目录中。
如果要将该值改为其他值,请相应地更改derby.jar文件的位置,否则部署后的演示应用程序将失败(因为它将无法找到必需的ApacheDerby类文件)。
接下来