中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> IBM专区 > DB2 > Java 技术
结合 DB2 UDB 使用 Java JoinRowSet 实现
作者:佚名 时间:2005-08-31 16:11 出处:互连网 责编:小渔
              摘要:结合 DB2 UDB 使用 Java JoinRowSet 实现
在断开连接的情况下执行连接

级别: 中级

Kulvir Bhogal
Software Services for WebSphere, Dallas, TX, IBM
2005 年 7 月 28 日

JSR114 为您在 Java™ 1.5 中带来了可串行化的断开连接对象。通过这些对象,可以连接到 DB2 UDB 数据库,将数据读取到本地。然后释放数据库连接,并离线地操纵数据。在此后的某个时间,又可以重新连接到数据库,并同步对断开连接对象做出的更改。在本文中,我将展示如何使用 JoinRowSet 接口对 IBM® DB2® Universal Database™ 数据执行离线 JOIN 操作。文中给出了示例代码。

简介
数据库编程人员对 SQL JOIN 语句的使用由来已久,通过该语句可以基于相同的属性将两个或更多关系数据库表中的数据组合到一起。过去,连接(join)操作必须在数据库服务器上执行。在前一篇 developerWorks 文章中,我向您介绍了 CachedRowSet Java 接口。CachedRowSet 是 Java 1.5 中新引入的接口,该接口让我们可以使用可串行化的非连接(disconnected)对象,这种对象能够存放数据库对象。CachedRowSet 对象支持对数据库对象的离线操作,并且可以与对象抓取的数据所在的数据库重新同步。通过阅读我撰写的在 http://www.ibm.com/developerworks/cn/db2/library/techarticles/dm-0406bhogal/ 上的文章,您可以了解更多关于 CachedRowSet 接口的信息。

在本文中,我将展示 CachedRowSet 接口的一个名为 JoinRowSet 的子接口。您将发现,通过 JoinRowSet Java 接口,可以在断开与数据库的连接时对来自数据库中的数据执行 JOIN 操作。这种 JOIN 操作发生在客户机上,而不是服务器上。读完本文之后,您可能会考虑在自己的应用程序架构中使用 JoinRowSet 对象。这样做可以为 IBM DB2 Universal Database Server 减轻计算负担。

家族简介
如前所述,JoinRowSet 接口是 CachedRowSet 接口的子接口。因此,您可以回顾我在关于 CachedRowSet 的文章中介绍的 CachedRowSet 接口所提供的功能。CachedRowSet 接口继承了 javax.sql.RowSet 接口,后者又是 java.sql.ResultSet 接口的子接口。

由于 Java 不允许实例化接口,所以为了进行我们的研究,需要拥有 JoinRowSet 接口的一个实现。在 Java 1.5 中,Sun 发布了 com.sun.rowset.JoinRowSetImpl 类(以下称之为 JoinRowSetImpl 类)。我们将着重研究 JoinRowSetImpl 类。其他供应商为 JoinRowSet 接口提供了不同的实现,这里主要研究 Sun 提供的参考实现。如果您使用的是 1.5 之前版本的 Java,而又想使用 JoinRowSet 和其他 RowSet 对象提供的功能,那么可以另外在 http://java.sun.com/products/jdbc/download.html 下载参考实现。

准备工作
为了研究 JoinRowSet 接口,需要一个数据库和一些表。假设我们要处理一个存放雇员信息的数据库,其中包含雇员姓名、薪水以及雇员所在部门 ID 等信息。部门信息放在一个不同的数据库表中,其中包括部门 ID 等信息。

表 1. EMPLOYEE 表
EMPLOYEENO LASTNAME FIRSTNAME DEPTID SALARY
111 Smith Terry LAB 36,343.00
222 Ruffin Ken LAB 49,425.00
333 Brown Hillary HR 57,626.00
444 Nguyen Jen ACC 65.312.00
555 Wallace Christine LEG 19,453.00

表 2. DEPARTMENT 表
DEPTID DEPTDESCRIPTION DEPTLOCATION
LAB Lab Operations Chicago
ACC Accounting Toronto
LEG Legal Miami
TRA Travel Boston

这里需要重点注意的是,在 both 表中有一个 DEPTID 列。

接下来创建一个数据库和两个表,用于存放上面表中的数据。

使用 DB2 命令行处理器,创建一个名为 JOINDB 的数据库。假设您有 DB2 管理员定义的名为 db2admin 的用户,其密码为 db2admin:


            db2 => connect to JOINDB user db2admin using db2admin
            

用以下命令创建 EMPLOYEE 表:


            db2 => create table EMPLOYEE (EMPLOYEENUM int primary key not null, LASTNAME varchar(30) not null,
            FIRSTNAME varchar(30) not null, DEPTID varchar(5) not null, SALARY decimal (8,2) NOT NULL)

为了填充这个表,使用语法:


            db2 => insert into EMPLOYEE values(111,'Smith','Terry','LAB',36343.00)

按照表 1 给出的数据,继续使用和上面类似的 insert 语法填充 EMPLOYEE 表中剩下的行。

接下来,用以下命令创建 DEPARTMENT 表。


            db2 => create table DEPARTMENT (DEPTID varchar(5) primary key not null,
            DEPTDESCRIPTION varchar(45) not null, DEPTLOCATION varchar(45) not null)
            

再通过如下 insert 命令用表 2 给出的数据填充 DEPARTMENT 填充:


            db2 => insert into DEPARTMENT values('LAB','Lab Operations','Chicago')
            

重温 JOIN 的功能
在深入研究 JoinRowSet 之前,先发出一条简单的 JOIN 命令,重温一下它的功能。之后我们将看到 JoinRowSet 函数如何执行与数据库服务器端 JOIN 操作相同的数据组合操作。

发出命令:


            db2 => select * from EMPLOYEE inner join DEPARTMENT on EMPLOYEE.DEPTID=DEPARTMENT.DEPTID

您将得到以下结果:

表 3. 服务器端 JOIN 查询的结果
EMPLOYEENO LASTNAME FIRSTNAME DEPTID SALARY DEPTID DEPTDESCRIPTION DEPTLOCATION
111 Smith Terry LAB 36,343.00 LAB Lab Operations Chicago
222 Ruffin Ken LAB 49,425.00 LAB Lab Operations Chicago
444 Nguyen Jen ACC 65.312.00 ACC Accounting Toronto
555 Wallace Christine LEG 19,453.00 LEG Legal Miami

注意,INNER JOIN 语句是使用 on EMPLOYEE.DEPTID=DEPARTMENT.DEPTID 子句发出的。这样便基于一个相同的属性(DEPTID 值)将两个表(EMPLOYEEDEPARTMENT)中的数据有效地组合起来。通过使用 INNER JOIN 语句,可以排除 EMPLOYEEEMPLOYEENO=333 的行,因为在 DEPARTMENT 表中没有 DEPTIDHR 的行。类似地,我们也没有看到包含名为 TRADEPTID 的行,因为在 EMPLOYEE 表中没有 DEPTIDTRA 的雇员。

在使用 JoinRowSet lingo 时,JOIN 操作是通过匹配列 DEPTID 来执行的。匹配列必须同时存在于被连接的各个表中。

使用 JoinRowSet
我们已重温了 JOIN 操作在服务器端的行为,现在来分析 JoinRowSet 如何在断开与数据库服务器的连接的客户端执行 JOIN 操作。这样的分析最好是通过一些 Java 代码示例来说明。所有的代码段都是和本文相关的 Java 类 JoinRowSetExample.java 的一部分。

JoinRowSet 对象可以用任何 javax.sql.RowSet 对象来填充(前提是 RowSet 对象可以是 SQL JOIN 操作的一部分)。CachedRowSet 接口对象是 RowSet 接口的一个子接口,同样也属于可用于填充 JoinRowSet 对象的 RowSet 对象。如果您不熟悉 CachedRowSet 的使用,那么建议您阅读我在 developerWorks 上撰写的关于 CachedRowSet 的 文章。在下面的代码中,我使用 CachedRowSetImpl(实现)类创建两个 CachedRowSet 对象,一个用于 EMPLOYEE 表,另一个用于 DEPARTMENT 表:


            Class.forName("com.ibm.db2.jcc.DB2Driver");
            CachedRowSet employees = new CachedRowSetImpl();
            employees.setUsername("db2admin");
            employees.setPassword("db2admin");
            employees.setUrl("jdbc:db2://localhost:50000/joindb");
            employees.setCommand("SELECT * from EMPLOYEE");
            employees.execute();
            CachedRowSet departments = new CachedRowSetImpl();
            departments.setUsername("db2admin");
            departments.setPassword("db2admin");
            departments.setUrl("jdbc:db2://localhost:50000/joindb");
            departments.setCommand("SELECT * from DEPARTMENT");
            departments.execute();
            

在上面的代码中,我通过指定连接信息和一个 SQL 查询填充 CachedRowSet 对象。或者,我也可以用一个已有的 ResultSet 对象填充 CachedRowSet 对象。注意,为了运行我提供的示例应用程序,必须将 DB2 Universal JDBC 驱动程序(db2jcc.jar)包括在运行时类路径中。您还需要包括 db2jcc_license_cu.jar 文件。要了解更多关于设置环境的信息,请参阅我的文章:Hooking Up with DB2 Universal Database Version 8 using Java。

至此,我们已经有了两个 CachedRowSet 对象,它们分别包括了表 EMPLOYEEDEPARTMENT 中的数据,现在可以创建 JoinRowSet 对象了。但是在这样做之前,我们先来演示一下断开与数据库的连接然后执行离线连接操作的能力。示例程序中有一个暂停,使您可以手动地停止 DB2,以便真正理解 JoinRowSet 带来的好处。当示例程序提示您停止 DB2 时,可以在一个新的命令行处理器窗口中使用以下命令:


            db2 force applications all
            

然后使用


            db2stop

强制停止 DB2。接下来,在我们的代码中,我们执行离线 JOIN


            JoinRowSet join = new JoinRowSetImpl();
            join.addRowSet(employees,"DEPTID");
            join.addRowSet(departments,"DEPTID");
            

首先我通过调用实现类 JoinRowSetImpl 的构造函数创建一个名为 joinJoinRowSet 对象。

接着,通过调用 addRowSet 方法,使用 JoinRowSet 类的 addRowSet 方法,该方法以我想添加的 RowSet 对象的名称作为第一个参数,以匹配列作为第二个参数。您可以看到,对于 employeesdepartments 对象,我都指定了匹配列 DEPTID

通过使用 Joinable 接口的 setMatchColumn 方法,也可以做同样的事情。由于 CachedRowSet 的实现类 CachedRowSetImpl 实现了 Joinable 接口,所以可以调用 JoinablesetMatchColumn 方法。


            JoinRowSet join = new JoinRowSetImpl();
            ((Joinable)employees).setMatchColumn("DEPTID");
            ((Joinable)departments).setMatchColumn("DEPTID");
            join.addRowSet(employees);
            join.addRowSet(departments);
            

在执行离线 JOIN 之后,我们可以像使用 ResultSet 对象一样,通过 getter 方法查看 JoinRowSet 对象中的数据。通过指定整数类型的列索引,或 String 对象类型的列名,就可以获得一个列的值。在下面的代码中我同时展示了这两种方法:


            // display records in JoinRowSet object
            while (join.next())
            {
            System.out.println(join.getInt(1) + " - " +
            join.getString("LASTNAME") + " - " +
            join.getString(3) + " - " +
            join.getString("DEPTID") + " - " +
            join.getFloat(5) + " - " +
            join.getString("DEPTDESCRIPTION") + " - " +
            join.getString(6));}
            

非连接对象 JoinRowSet 的输出与我们在服务器端执行 JOIN 查询得到的数据完全一致(与表 3 比较):


            555 - Wallace - Christine - LEG - 19453.0 - Legal - Legal
            444 - Nguyen - Jen - ACC - 65312.0 - Accounting - Accounting
            222 - Ruffin - Ken - LAB - 49425.0 - Lab Operations - Lab Operations
            111 - Smith - Terry - LAB - 36343.0 - Lab Operations - Lab Operations
            

修改断开连接对象 JoinRowSet
由于 JoinRowSet 接口是 CachedRowSet 接口的一个子接口,所以我们继承了离线地修改(插入、删除和更新)由 JoinRowSet 对象表示的记录并与数据库重新同步的能力,就像使用 CachedRowSet 对象时可以获得的能力一样。在我的关于 CachedRowSet 的 文章 中,您可以了解更多关于如何执行数据插入、删除和更新的信息。JoinRowSet 接口与 RowSet 接口的这种关系带来的主要好处是可以离线执行数据操纵,然后将做出的更改与数据库重新同步。

跨数据库连接
JoinRowSet 似乎允许的另一个有趣的功能是跨数据(甚至可以是不同供应商提供的数据库)执行离线 JOIN 操作。我没有看到这方面的文档,所以我会小心地使用这项技术,但是我可以在一个 MySQL 数据库表和一个 DB2 数据库表之间执行 JOIN 操作。由于 MySQL 数据库表和 DB2 数据库表中存在相同的匹配列,所以这样做是可行的。两个表中的匹配列都需要有相同的列定义(例如,MySQL 数据库表 DEPARTMENT 中的 DEPTID 列也应该和 DB2 数据库表中相应的列一样定义为 varchar(45))。

JoinRowSetImpl 的缺陷
在本文编写之际,JoinRowSetImpl 类有一个 bug,它允许指定多个列作为无用的 MatchColumn。我想将来发布的这个类会修复这个 bug。如果这个 bug 还在的话,那么您可以为离线连接操作指定一个或多个列作为匹配列。

同样是在本文编写之际,JoinRowSetImpl 类只实现了执行内 JOIN(也就是本文用例子展示的那种连接) 的能力。那些熟悉 JOIN 操作的能力的人也许会问,“LEFT JOINRIGHT JOIN 等等实现了没有?”将来的 JoinRowSetImpl 有望实现这些类型的 JOIN,但是就目前而言,我们只能使用 INNER JOIN

结束语
从本文可以看出,JoinRowSet 接口允许 Java 应用程序在断开连接对象上执行 JOIN 操作,而无需保持数据库连接。通过在应用程序中适当地使用 JoinRowSet,可以减轻数据库服务器上由 JOIN 操作带来的负担。JOIN 操作的负担完全转移到了客户机应用程序。

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有