内容


在 Eclipse 中开发 Apache Derby 应用程序

Comments

概述

本文的目的是向您展示如何在 Eclipse 集成开发环境(IDE)中使用几种不同的工具,例如 Java Development Tools、IBM? DB2? plug-ins for Eclipse 和 IBM integration plug-in for Derby,以便开发 Apache Derby 应用程序。

本文将介绍一个典型 Derby 应用程序的整个开发周期,从数据库的创建开始,然后经历 JDBC 客户机应用程序的开发,存储过程和函数的开发,最后是解决方案的开发。本文还将描述必要时如何用 DB2 Universal Database (UDB) 数据库替代 Apache Derby 数据库。

本文假设您对 Apache Derby 数据库、Eclipse 平台和 DB2 plug-ins for Eclipse 有基本的理解。强烈建议您阅读 参考资料 一节中列出的文章“与 Apache Derby 一起使用 DB2 plug-ins for Eclipse”的两个部分。

为了阐明应用程序开发中涉及的各种不同任务,作者 Gilles Roux 将提供关于如何构建一个示例应用程序的具体例子和逐步说明。

在这个例子中,您需要开发一个命令行应用程序来执行一家书店的库存管理。书店的数据库存储了这家书店拥有的各种书籍,以及这些书籍的现有数量。

这个示例应用程序将允许您访问这些数据,并允许您更改书籍的数量。例如,如果从一个供应商那里收到一批书,那么就要使用这个应用程序来添加所收到书籍的数量。如果书籍的数量超过或者低于某个限制,则需要用电子邮件通知管理员,以便其采取必要的行动。

开发环境

工具

Java Development Tools(JDT)是一组内建到 Eclipse 中的插件,为编辑、编译、调试、执行和部署一般用途的 Java 应用程序提供了一种方法。

DB2 plug-ins for Eclipse 提供了连接到各种数据库(包括 IBM Cloudscape 和 Apache Derby)的一组功能。这个插件是以下几个插件的组合。

  • Connection Wizard:用于创建和连接 DB2、Cloudscape 或 Derby 数据库。
  • Database Explorer View:用于浏览数据库对象。
  • SQL Scrapbook:用于编辑和执行单独的 SQL 语句。
  • Database Output View:用于对一个表的内容进行抽样或者查看一条 SQL 语句的执行结果。
  • Migration Wizard:用于自动地将一个现有 Derby 数据库迁移到 DB2 UDB。

IBM integration plug-in for Derby 将很多有用的 Derby 工具集成到了 Eclipse 环境中。下面是该工具所提供的主要功能:

  • Apache Derby Nature:使 Eclipse 项目可以执行 Derby 任务。
  • Network Server:直接从 Eclipse 项目中配置和启动 Derby Network Server。
  • IJ:直接在 Eclipse 控制台中以交互模式或脚本模式启动 Derby 命令行实用程序。
  • Sysinfo:显示与项目相关的 Derby 系统信息。

DB2 plug-ins for Eclipse 和 IBM Integration plug-in for Derby 是两个独立的工具,但是它们之间互补性很强,前者提供了一般数据库连接,而后者则提供了访问很多特定于 Derby 特性的访问途径。

然而,很多任务都可以通过这些工具中的任意一个来执行,效果是一样的。本文提到了执行一个给定任务的各种不同方法,从而使每个用户都可以选择他们所喜爱的工作方式。

安装工具

首先要下载和安装 DB2 plug-ins for Eclipse。该产品包括 DB2 插件,并且是基于 Eclipse 3.0 的,后者本身就包括了 JDT。

然后从 Apache.org 下载 Apache Derby plug-in,并在安装了前面软件的基础上安装此软件。

最后,下载 IBM Integration plug-in for Derby 并在安装了 eclipse 的基础上安装此软件。该插件包括 JCC JDBC 驱动程序和 Derby 集成工具。

设置开发环境

如前所述,您将使用几种不同的工具来开发应用程序:DB2 plug-ins for Eclipse、IBM Integration plug-in for Derby 和 JDT。这些工具都是基于 Eclipse 的,因此它们可以很好地集成到一个单独的开发环境中。

在开发应用程序时,通常要建立一些到数据库的连接:

  • 使用 Database Explorer 浏览数据库。
  • 使用 Derby ij 命令行实用程序执行 SQL 语句。
  • 在测试时应用程序自己将连接到数据库。

Derby 数据库引擎可以在多种配置下运行。最简单的一种是嵌入式配置,但在这里不适合,因为需要通过运行在不同 Java 虚拟机上的几种工具建立连接。而且,在生产环境中,可能需要从多个应用程序中访问数据库。因此,这里使用 Network Server 配置。IBM Integration plug-in for Derby 提供了一种选择,以便可以很容易地从 Eclipse 项目目录中启动本地机器上的 Derby Network Server。接着要配置应用程序和其他工具,以连接到该网络服务器。下图展示了配置情况。

图 1. 开发环境配置
开发环境配置
开发环境配置

设置环境的第一步是创建项目。选择“File->New->Project->Java Project”并输入 bookstore 作为项目名称。这样就创建了一个 Java 项目,然后切换到 Java perspective(透视图)中。右击该项目并选择“Apache Derby->Add Apache Derby nature”。这样使您的项目可以使用 Apache Derby 特性,然后设置该 Java 项目的构建路径,以便应用程序可以访问 Derby 数据库和 JDBC 驱动程序。

DB2 plug-ins for Eclipse 通常可以从 Data perspective 访问,并且无需与某个特定的项目相关联。为了简化开发过程,避免 Java perspective 和 Data perspective 之间的切换,需要将 DB2 plug-ins 视图,即 Database Explorer 视图和 DB Output 视图,添加到 Java perspective。这可以通过 Show View->Other 菜单来完成。下图展示了开发环境的外观。

图 2. 开发环境布局
开发环境布局
开发环境布局

创建数据库

在开始编写实际的应用程序代码之前,需要创建应用程序将要用到的数据库,或者连接到一个已有的数据库。

首先通过右击项目并选择“Apache Derby->Start Derby Network Server”来启动 Derby Network Server。每次重新启动 Eclipse 时都需要执行这一步。这时项目图标上有一个绿色的箭头,表明服务器正在运行。

创建数据库

创建一个 Derby 数据库非常类似于连接到一个已有的数据库:通过将 create=true 属性包括在 URL 中,可以指示数据库引擎在您第一次连接到数据库时创建该数据库。这可以通过使用 DB2 plug-ins for Eclipse 的 Connection Wizard 来完成。下面的表展示了在这个向导中应该使用的参数。

表 1. 连接参数
Connection namebookstoredb
Database ManagerApache Derby v10.0
JDBC DriverIBM DB2 Universal需要使用这个参数来连接到网络服务器
Databasebookstoredb要创建的数据库的名称
Hostlocalhost网络服务器运行在本地机器上
Port Number1527默认端口号
Class Location比如: C:\eclipse\plugins\ com.ibm.cloudscape.ui_1.0.0\db2jcc_license_c.jar;C:\eclipse\plugins\com.ibm.cloudscape.ui_1.0.0 \db2jcc.jar
Create database if requiredyes需要使用这个参数在第一次连接时创建数据库
User IDbookstore数据库上的认证没有被启用,因此可以使用任何用户,但是用户名将定义默认模式
Passwordaaa数据库上的认证没有被启用,因此可以使用任何密码
图 3. 使用 Connection Wizard 创建数据库
使用 Connection Wizard 创建数据库
使用 Connection Wizard 创建数据库

完成该向导后,便创建了一个数据库,并且向 Database Explorer View 中添加了一个连接。通过展开连接的节点,就可以浏览这个数据库,但是显然这个时候它是空的。

数据库被创建在 Derby 网络服务器的当前目录中,也就是之前创建 Eclipse 项目时所在的目录。可以通过右击项目名并选择 Refresh 来刷新该项目,这样将显示一个新的 bookstoredb/ 目录,该目录包含用于数据库的文件。不要试图修改这些文件,否则数据库会受到损坏。

创建数据库对象

接下来的步骤是创建应用程序将要用到的数据库对象。在这里,只需使用 SQL Scrapbook 创建一个表即可。SQL Scrapbook 可以通过右击连接名并选择“Open SQL Scrapbook”来调用。这时将打开一个新的编辑器,在这个编辑器中可以输入要发出的 SQL 语句:

清单 1. CREATE TABLE 语句
create table books(
    id int,
    title varchar(128),
    author varchar(128),
    price decimal(6,2),
    quantity int,
    status int
)

请注意,SQL Scrapbook 只能用于执行单条的 SQL 语句。而且,不要以分号来结束 SQL 语句。然后,可以按下主 Eclipse 按钮栏中的“Execute SQL statement”按钮。DB Output 视图应该显示结果是成功的。还可以刷新连接,以及验证数据库现在是否包含新创建的表。

图 4. 使用 SQL Scrapbook 创建表
使用 SQL Scrapbook 创建表
使用 SQL Scrapbook 创建表

创建测试数据

现在通过执行 INSERT 语句向 books 表填充一些测试数据。这也可以通过 SQL Scrapbook 来实现,但这里我们使用了 IBM Integration plug-in for Derby 的“Run SQL script using ij”功能。这项功能允许使用 Derby 命令行实用程序执行 SQL 脚本,并在 Eclipse 输出视图中查看结果。这种方法的一大优点是:它允许一次执行多条语句。而且,这种方法要求在脚本的开始处包含一条连接语句,因此您可以对连接 URL 有更多的控制。

表 2. SQL Scrapbook 和 IJ 脚本 之间的不同之处
SQL Scrapbook执行 IJ 脚本
语句存储在一个文件中不是
一次可以执行多条语句不是
语句终止符不允许有终止符分号
编辑功能语法高亮显示,内容辅助没有
到数据库的连接SQL scrapbook 被关联到一个给定的连接第一条语句应该是到所需数据库的一个连接

构建 URL 的一种简便方法是复制 Connection Wizard 所使用的 URL:在数据库浏览器中右击连接,然后选择“Edit Connection”并访问“Connection URL”字段。这里需要添加用户名和密码作为 URL 属性。

使用 Eclipse 在项目中创建一个名为 data.sql 的文本文件,并键入以下命令:

清单 2. INSERT INTO 语句
connect 'jdbc:derby:net://localhost:1527/bookstoredb:user=bookstore;password=aaa;';
insert into books values(1, 'East Of Eden', 'John Steinbeck', 7.20, 3, 0);
insert into books values(2, 'Hard-Boiled Wonderland and the End of the World',
    'Haruki Murakami', 10.50, 9, 0);
insert into books values(3, 'SQL for Dummies', 'Allen G. Taylor', 16.49, 6, 0);
disconnect;

然后就可以在 Project Explorer 中右击该文件并选择“Apache Derby->Run SQL script using ij”。Eclipse 的控制台输出视图将显示执行的结果,这个结果应该是成功的。然后可以在 Database Explorer 中选择 books 表,并选择“Sample Content”,以确信数据真正被插入到这个表中。

图 5. 执行 SQL 脚本以插入数据
执行 SQL 脚本以插入数据
执行 SQL 脚本以插入数据

编写 Derby Client JDBC 应用程序

装载 JDBC 驱动程序

通过使用 Eclipse JDT 和 Derby JDBC 驱动程序,可以很容易地编写 JDBC 应用程序。首先使用 JDT Class 向导在 bookstoreapp.clientside 包中创建一个 Inventory 类,并在类中添加一个 main() 方法。由于启用了 Derby nature,所以包含 JDBC 驱动程序和 Derby 类的 JAR 文件已经位于项目的类路径中。

在连接到一个 Derby 数据库之前,需要使用 Class.forName(jdbcDriverClassName) 方法装载适当的 JDBC 驱动程序。该方法将装载参数指定的 JDBC Driver 类,并注册这个类,以便进行下一次 JDBC 连接。

可以使用两种不同的 JDBC 驱动程序,这取决于 Derby 配置:

表 3. Derby JDBC 驱动程序
配置Embedded ServerNetwork Server
所需 JAR 文件derby.jardb2jcc.jar;db2jcc_license_c.jar
类名org.apache.derby.jdbc.EmbeddedDrivercom.ibm.db2.jcc.DB2Driver

由于这个例子是基于一个网络服务器配置,因此这里使用 jcc JDBC 驱动程序。如果不确定的话,那么正确的类名可以通过从 Connection 向导复制获得:

清单 3. 装载 jcc JDBC 驱动程序
Class.forName("com.ibm.db2.jcc.DB2Driver");

连接到数据库

DriverManager.getConnection(url) 方法用于建立到数据库的连接。它假设一个连接 URL,并返回一个 Connection 对象,这个对象可用于查询数据库。

获得连接 URL 的一种好方法是在 Database Explorer 视图中编辑 Derby 连接,并复制从各个连接属性自动构造而成的连接 URL。出于安全的原因,这里没有显示用户名和密码,因此在应用程序代码中需要手动地将它们添加到 URL 的后面。

图 6. 使用连接向导构建连接 URL
使用连接向导构建连接 URL
使用连接向导构建连接 URL

其他选项也可以添加到 URL 的后面。例如,retrieveMessagesFromServerOnGetMessage=true 选项指示 JDBC 驱动程序从 Derby 服务器获取可读的错误消息,这在调试连接到远程 Derby 数据库的应用程序时非常有用。

在本文的例子中,使用下列代码连接到 Derby 数据库:

清单 4. 连接到数据库
String url = "jdbc:derby:net://localhost:1527/bookstoredb";
url += ":user=bookstore;password=aaa;";		
url += "retrieveMessagesFromServerOnGetMessage=true;";
Connection con = DriverManager.getConnection(url);

查询数据库

一旦建立了连接,便可以通过使用 JDBC API 查询数据库。例如,您可以创建一个 Statement 对象,然后使用这个对象来执行对数据库的 SQL 查询。查询返回一个用于迭代查询结果集的 ResultSet 对象:

清单 5. 执行查询并迭代结果集
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM bookstore.books");
while (rs.next()) {
    System.out.print(rs.getString(1) + ", ");
    System.out.print(rs.getString(2) + ", ");
    System.out.print(rs.getString(3) + ", ");
    System.out.print(rs.getString(4) + ", ");
    System.out.print(rs.getString(5) + ", ");
    System.out.println(rs.getString(6));
}
rs.close();
stmt.close();
图 7. 运行 JDBC 应用程序
运行 JDBC 应用程序
运行 JDBC 应用程序

要了解关于使用 JDBC 的更多信息,请参阅本文 参考资料 一节中列出的 JDBC 教程。

您可以下载 Inventory 类的完整代码。这个类实现了一个简单的文本界面,用于列出书店中的书籍以及更新书店中给定的某种书籍的数量。

下面是应用程序输出的一个例子:

图 8. Inventory 应用程序的示例输出
Inventory 应用程序的示例输出
Inventory 应用程序的示例输出

编写 Java 函数和过程

前一节中讨论的 JDBC 应用程序对于开发用于用户的前端应用程序非常有用。然而,在这一层中实现重要的应用程序逻辑不是很妥当,因为应用程序逻辑放置在数据库之外,这使得数据库更容易受到损坏。例如,如果另一个 JDBC 应用程序连接到同一个数据库,那么就需要确保它实现相同的逻辑。对于这个问题,一种解决办法是通过使用触发器、存储过程和函数,在数据库中实现数据库规则。

编写 Java 代码

由于 Derby 是一种 Java 数据库,因此它没有自己的存储过程/函数语言,而是使用 Java 语言。可以通过创建一个 Java 方法,然后基于这个 Java 方法声明一个 Derby 过程或函数,从而创建 Derby 存储过程或函数(通常称为例程)。对 Derby 例程的调用将导致这个 Java 方法被调用。

为了让这种调用获得成功,重要的是让 Derby 和 Java 例程的声明相匹配。下面的表展示了应该使用的 Derby 和 Java 特性的映射。

表 4. 用于编写 Java 函数和过程的特性映射
DerbyJava
过程没有返回值的公共静态方法
函数有一个返回值的公共静态方法
输入参数(过程或函数)方法参数
输出参数(过程)单入口数组参数
输入/输出参数(过程)单入口数组参数
返回值(函数)返回值
返回的结果集附加的单入口 java.sql.ResultSet[] 参数
表 5. 用于编写 Java 函数和过程的类型映射
DerbyJava
SMALLINTshort
INTEGERint
BIGINTlong
DECIMAL(p,s)java.math.BigDecimal
REALfloat
DOUBLE PRECISIONdouble
CHAR(n)String
VARCHAR(n)String
LONG VARCHAR*unsupported*
CHAR(n) FOR BIT DATAbyte[]
VARCHAR(n) FOR BIT DATAbyte[]
LONG VARCHAR FOR BIT DATA*unsupported*
CLOB(n)*unsupported*
BLOB(n)*unsupported*
DATEjava.sql.Date
TIMEjava.sql.Time
TIMESTAMPjava.sql.Timestamp

对于 Java 方法本身的内容没有约束,因此任何合法的 Java 代码都可以作为 Derby 过程或函数来调用。一种有趣的应用是使用标准 derby:default:connection URL 建立到 Derby 数据库的 JDBC 连接,以便查询发出调用的数据库。还可以使用完整 JDBC URL 连接到另一个数据库。

对于本文的应用程序,需要在 bookstoreapp.serverside 包中创建一个 DerbyFunctions 类,用于容纳数据库服务器将要运行的所有 Java 方法。然后可以创建一个 updateQuantity 方法,当更新一种书籍的数量时,将调用该方法。调用该方法时需要提供这种书籍的 IDtitleauthor,以及旧的数量和新的 quantity。这个方法将返回一个整数值,用于表明是否到达数量限制。

因此,这个 Java 方法的声明如下:

清单 6. Java 方法的声明
public static int updateQuantity(int id, String title, String author,
    int oldQuantity, int newQuantity)

这个函数的作用是:当书的数量达到一个下界或上界时,就发送一封电子邮件。因此,可以声明 LOW_LIMITHIGH_LIMIT 常量,并测试旧的数量是否低于下界,新的数量是否高于上界或低于下界。如果条件符合,那么可以调用另一个负责发送电子邮件的 Java 方法。在这个例子中,只是输出一条调试消息,而不发送真正的电子邮件。

下面是完整的代码:

清单 7. DerbyFunctions 类
package bookstoreapp.serverside;
public class DerbyFunctions
{
	
    public static final int LOW_LIMIT = 2;
    public static final int HIGH_LIMIT = 10;
    public static int updateQuantity(int id, String title, String author,
	                                 int oldQuantity, int newQuantity)
    {
        if ( oldQuantity<HIGH_LIMIT && newQuantity>=HIGH_LIMIT )
            sendEMailAlert("High limit reached", "title: "+title+", author: "+author);
        else if ( oldQuantity>LOW_LIMIT && newQuantity<=LOW_LIMIT )
            sendEMailAlert("Low limit reached", "title: "+title+", author: "+author);
        if (newQuantity>=HIGH_LIMIT)
            return +1;
        else if (newQuantity<=LOW_LIMIT)
            return -1;
        else 
            return 0;
    }
    
    public static void sendEMailAlert(String subject, String msg)
    {
        System.out.println("Sending email: " + subject);
        System.out.println(msg);
    }
    
}

从 main 方法中调用这个 Java 方法,以便对其进行测试,这通常是一种很好的做法。

创建 Derby 函数

创建 Derby 存储过程或函数比较容易,只需指定名称、参数、返回值和相应 Java 方法的全限定名称即可。Derby 例程的标签必须与 Java 方法的标签相匹配,以便数据库可以成功地调用 Java 代码。

可以很容易地从 SQL Scrapbook 发出 CREATE 语句,但是在这个例子中,最好使用 ij 实用程序。如果使用 ij 实用程序,便可以显式地指定连接 URL,从而允许我们包括 retrieveMessagesFromServerOnGetMessage=true 属性。该选项导致 JDBC 驱动程序从服务器获取完整的错误消息,当语句执行失败时,这一点很有帮助。

下面是在 ij 中发出的命令:

清单 8. 在 Derby 中创建 Java 函数
connect 'jdbc:derby:net://localhost:1527/bookstoredb
    :user=bookstore;password=aaa;retrieveMessagesFromServerOnGetMessage=true;';
create function updateQuantity(id int, title varchar(128), author varchar(128),
    oldQuantity int, newQuantity int) returns int
PARAMETER STYLE JAVA NO SQL LANGUAGE JAVA
EXTERNAL NAME 'bookstoreapp.serverside.DerbyFunctions.updateQuantity';

Derby 函数的创建应该可以成功,但有时候我们很难一开始就能保证语句完全正确。下面是可能发生的一些常见错误:

  • ERROR 42962: Long column type column or parameter 'I' not permitted in declared global temporary tables or procedure definitions. 如果使用一种不受支持的参数类型声明一个 Derby 过程,就会发生这种错误。
  • ERROR 42X50: No method was found to be able to match method call pack.A.p(int), even tried all combinations of object and primitive types and any possible type conversion for any parameters the method call may have. It may be that the method exists, but it is not public and/or static, or that the parameter types are not method invocation convertible. 当调用一个过程/函数时,如果 Derby 不能找到与过程/函数声明相匹配的 Java 方法,就会发生这种错误。错误消息给出了不能找到的 Java 方法的标签。

请注意,如果更改了方法的 Java 代码,那么就需要停止并重新启动 Derby 网络服务器,以便数据库引擎的类装载器装载新的代码。

成功地创建了 Derby 例程之后,就可以通过 ij 命令行调用这个例程,以便对其进行测试。可以通过使用 CALL 语句来调用 derby 过程,但在这里因为需要测试一个函数,因此发出以下命令:

清单 9. 调用 Derby 中的 Java 方法
values(updateQuantity(1, 'title', 'author', 5, 15));

IJ 显示返回值,在这里,这个返回值为 1,因为数量到达了上界。由于这个 Java 方法是在 Derby 服务器 JVM 中运行的,因此调试消息将被输出到服务器的标准输出中。使用 eclipse 控制台视图切换到 Derby 网络服务器控制台,您应该可以看到一条 Sending email... 消息。

还可以尝试使用以下代码从 JDBC 应用程序中调用 Derby 函数:

清单 10. 从客户机应用程序中调用 Java 方法
stmt.executeQuery("values(updateQuantity(1, 'title', 'author', 5, 15)); ");

结果应该与前面测试中的结果一致。

从 Derby 触发器中调用函数

本节最后一步是配置 Derby,以便每次更新某种书籍的数量时,调用之前定义的函数。这可以用一个触发器来实现。

derby 触发器包含关于要执行的动作以及何时执行动作的信息。

表 6. CREATE TRIGGER 语句的子句
INSERT、DELETE 或 UPDATEUPDATE
REFERENCING 子句OLD AS OLD, NEW AS NEW。为了调用那个函数,需要能够引用旧的和新的数量
FOR EACH 子句FOR EACH ROW。即使有多行被更新,对函数的调用也是逐行进行的
动作update books set status = updateQuantity(…) where id = NEW.id;

下面是在 ij 中发出的用于创建触发器的语句:

清单 11. CREATE TRIGGER 语句
create trigger updateQuantityTrig after update of quantity on books
referencing OLD as OLD NEW as NEW for each row mode db2sql
update books set status = updateQuantity(NEW.id, NEW.title, NEW.author,
    OLD.quantity, NEW.quantity) where id = NEW.id;

检查触发器是否有效的一种简便方法是使用以下命令从 ij 工具中更新 book 表:update books set quantity=10 where id=1; 对表的修改将触发函数的调用,从而导致执行 Java 方法。这将更新书的状态,并发送一条消息,这条消息可以通过切换到网络服务器控制台视图来查看。

由于触发器直接存储在数据库中,因此无论如何更新数据,对触发器的调用都将是一致性的。由于这个原因,如果您试图使用客户机应用程序更新数量,那么您将看到,适当的时候就会生成电子邮件消息,不需要对应用程序作任何更改。

下图展示了客户机应用程序的输出,用的是原始数据。注意,这一次书的状态会获得更新,并生成了一条消息:

图 9. Inventory 应用程序的示例输出
Inventory 应用程序的示例输出
Inventory 应用程序的示例输出
图 10. Network Server 的示例输出
Network Server 的示例输出
Network Server 的示例输出

部署应用程序

至此,您已经有了一个功能完备的数据库和客户机应用程序,但它们仍然只能在 Eclipse 环境中运行,在生产环境中不被接受。因此,还需要执行应用程序的部署。

将 Java 函数存储在数据库中

如前所述,Derby Java 函数或过程是由数据库引擎自身来执行的。因此,数据库引擎必须能够访问 Java 类。在这个例子中,这一点是没有问题的,因为 Derby 网络服务器运行在 Eclipse 项目中,并且使用项目的类路径,该类路径包含了已创建的所有 Java 类。

在一个典型的生产环境中,您不需要更改用于 Derby 网络服务器的类路径。Derby 提供了一些可以解决这个问题的过程:

  • sqlj.install_jar 过程将一个 JAR 文件安装到数据库中。JAR 文件在安装好之后便无法修改,但是可以使用 sqlj.remove_jarsqlj.replace_jar 来删除或更新 JAR。
  • derby.database.classpath 属性包含数据库将要使用的附加类路径条目。可以通过使用 syscs_util.syscs_set_database_property 过程更新这个属性,以便更新属性和包含已安装的 JAR。

对于本文中的例子,首先要创建一个 JAR 文件,这个 JAR 文件包含 DerbyFunctions 类。这可以在 Eclipse 中通过右击这个类并选择 Export->JAR file 来完成创建任务。

然后可以使用下列命令(在 ij 中)将 JAR 文件安装到数据库中,并将其添加到类路径中:

清单 12. 将 JAR 文件存储在 Derby 数据库中
CALL sqlj.install_jar('functions.jar', 'bookstore.functionsjar', 0);
CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY(
    'derby.database.classpath', 'bookstore.functionsjar');

做完这些后,Java 代码便属于数据库,这使得数据库的转移和启动变得很容易。整个数据库目录可以直接转移到一个完全不同的环境中,并且可以正常运行。

网络服务器配置

在开发应用程序时,我们使用了网络服务器配置,这样一来,应用程序的部署就会按正确的方式打包各个组件。

在服务器端,需要安装:

  • derby.jar,其中包含 Derby 数据库引擎。
  • derbynet.jar,其中包含网络服务器。
  • bookstoredb/ 目录,其中包含数据库,还包括带有函数的 JAR 文件。

这些组件可以复制到任何装有 JVM 的机器上,网络服务器可以使用下列命令来启动:

清单 13. 启动 Derby 网络服务器
java -cp derby.jar;derbynet.jar org.apache.derby.drda.NetworkServerControl start

可以使用下列命令可以停止网络服务器:

清单 14. 停止 Derby 网络服务器
java -cp derby.jar;derbynet.jar org.apache.derby.drda.NetworkServerControl shutdown

在客户端,需要安装:

  • db2jcc.jardb2jcc_license_c.jar,用于 JDBC 驱动程序。
  • inventory.jar,这个 jar 包含了应用程序的各个类。通过使用 eclipse 导出功能,可以很容易地基于应用程序包创建这个 JAR。

这些组件可以复制到任何装有 JVM 的机器上。当网络服务器正在运行时,可以使用以下命令启动应用程序:

清单 15. 启动客户机应用程序
java -cp db2jcc.jar;db2jcc_license_c.jar;inventory.jar bookstoreapp.clientside.Inventory

下图阐明了网络服务器配置中应用程序的部署:

图 11. 网络服务器部署配置
网络服务器部署配置
网络服务器部署配置

下图展示了应用程序在生产环境中的执行:

图 12. 已部署的网络服务器的执行
已部署的网络服务器的执行
已部署的网络服务器的执行
图 13. 已部署的客户机应用程序的执行
已部署的客户机应用程序的执行
已部署的客户机应用程序的执行

嵌入式服务器配置

网络服务器配置也许最适合这种类型的应用程序,但是也可以使用嵌入式服务器配置,比如出于性能方面的原因。

在部署应用程序之前,需要在代码中作一下修改,使连接指向嵌入式服务器,而不是远程服务器。这可以通过修改 JDBC 驱动程序类名和连接 URL 来实现这一点:

清单 16. 新的连接代码
Class.forName("org.apachy.derby.jdbc.EmbeddedDriver");
String url = "jdbc:derby:bookstoredb";

完成这些修改之后,便可以使用 Eclipse 导出功能将应用程序的类打包到 JAR 文件中,并将下列文件部署到生产机器上:

  • derby.jar,其中包含 Derby 数据库引擎和 JDBC 驱动程序。
  • inventory.jar,其中包含应用程序的类。
  • bookstoredb/ 目录,其中包含数据库,还包括带有存储过程和函数的 JAR 文件。

可以使用下列命令启动应用程序:

清单 17. 启动应用程序
java -cp derby.jar;inventory.jar  bookstoreapp.clientside.Inventory

下图阐明了应用程序在嵌入式服务器配置中的部署:

图 14. 嵌入式服务器部署配置
嵌入式服务器部署配置

迁移到 DB2

虽然 Apache Derby 是一种非常健壮的、可伸缩的数据库,但是由于以下原因,您有理由转而使用企业数据库,例如 DB2 UDB:

  • 功能缺乏。
  • 性能受限。
  • 需要与其他数据库集成。

由于有了 DB2 plug-ins for Eclipse,并且客户机应用程序是基于标准 JDBC 接口的,所以从 Derby 到 DB2 的迁移很容易完成。

迁移数据库

第一步是迁移数据库本身。DB2 plug-ins for Eclipse 提供了一个工具来自动地将 Apache Derby 数据库迁移到 DB2 for Linux、Unix 和 Windows。

首先通过在 DB2 CLP 中发出 create database bookstoredb 命令创建一个 DB2 数据库。

然后可以通过在 Database Explorer 视图中右击之前创建的 derby 数据库条目并选择 ‘Migrate to DB2 UDB…’ 动作来调用迁移工具。确保 DB2 服务器已经启动,并遵循使用说明来创建 DB2 数据库、迁移数据库对象和迁移实际数据。

图 15. 使用 DB2 plug-ins for Eclipse 迁移 Derby 数据库
使用 DB2 plug-ins for Eclipse 迁移 Derby 数据库
使用 DB2 plug-ins for Eclipse 迁移 Derby 数据库

手动迁移不受支持的对象

完成了数据库的迁移之后,迁移工具会给出一个报告,指出迁移获得成功,但是有些对象不能迁移。当前版本的迁移工具不支持触发器和函数,因此需要手动迁移这些对象。

Apache Derby SQL 语言是与 DB2 兼容的语言,因此可以重复使用以前的 SQL 语句来创建丢失的对象。在 Database Explorer 中右击 DB2 连接,并打开一个新的 SQL Scrapbook。

包含 Java 函数的 JAR 文件的安装与 Derby 的安装类似,惟一的区别是无需将 JAR 文件添加到类路径。从 DB2 连接打开一个 SQL scrapbook,并输入以下命令:

清单 18. 在 DB2 中安装 JAR 文件
CALL sqlj.install_jar('functions.jar', 'bookstore.jar1', 0)

为了创建函数和触发器,只需将之前使用的 SQL 语句复制和粘贴到 SQL scrapbook 中。记住,一次只能执行一条语句,因而不能使用冒号作为结束符。

清单 19. 在 DB2 中创建函数和触发器
create function bookstore.updateQuantity(id int, title varchar(128), author varchar(128),
    oldQuantity int, newQuantity int) returns int
PARAMETER STYLE JAVA NO SQL LANGUAGE JAVA
EXTERNAL NAME 'bookstoreapp.StoredProcs.updateQuantity'
create trigger bookstore.updateQuantityTrig after update of quantity on books
referencing OLD as OLD NEW as NEW for each row mode db2sql
VALUES(updateQuantity(NEW.id, NEW.title, NEW.author, OLD.quantity, NEW.quantity))

迁移客户机应用程序

迁移客户机应用程序的主要工作是修改建立数据库连接的那部分代码:

  • 既然不再使用 Derby,那么右击 bookstore 项目并选择“Apache Derby->Remove Apache Derby nature”。这将从构建路径中删除 Derby JAR 文件。
  • 编辑项目的 Java 构建路径,并添加 DB2 JDBC 驱动程序 jar 文件:db2jcc.jar and db2jcc_license_cisuz.jar,对于 Windows 机器,这两个文件通常可以在 C:\Program Files\IBM\SQLLIB\java\ 目录下找到。
  • 在 Java 代码中,将 JDBC 驱动程序的类名更改为 com.ibm.db2.jcc.DB2Driver
  • 再将连接 URL 更改为:jdbc:db2://localhost:50000/BOOKSTORE,并更改用户名和密码。
  • 由于可能没有 bookstore 用户名,因此需要更改 DB2 默认模式。这可以通过在客户机应用程序初始化时发出以下命令来完成:stmt.execute("SET CURRENT SCHEMA = bookstore");

虽然 JDBC API 允许以相同的方式连接到任何数据库,但发送到数据库的实际的 SQL 查询必须遵从数据库 SQL 语言。因此,迁移 JDBC 应用程序时需要重新编写某些 SQL 查询。在这个例子中,Derby 语言是 DB2 语言的一个子集,因此不存在这方面的问题,您无需对 SQL 查询作任何修改。

现在应用程序应该可以进行编译,并且可以成功地在 DB2 数据库上运行。还可以像在 Derby 网络服务器配置中那样部署应用程序。

结束语

在阅读本文之后,您应该能够有效地使用为 Derby 提供的基于 Eclipse 的不同工具开发 Apache Derby 应用程序。您还应该可以执行一些相关的任务,例如在各种可能的配置中部署这种应用程序,或者将数据库和应用程序迁移到 DB2 UDB。


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Information Management, Java technology, Open source
ArticleID=57799
ArticleTitle=在 Eclipse 中开发 Apache Derby 应用程序
publish-date=02012005