DB2 9 提供了 java 应用程序开发人员很容易上手的新的 xml 支持。这是因为 DB2 9 允许程序员使用熟悉的 JDBC 语句和业界标准的查询语言来查询、插入、更新和删除 XML 数据以及传统的 SQL 数据。
在本文中,我将展示关于如何使用 Java 构建采用 DB2 “pureXML” 技术的应用程序的详细例子,pureXML 技术允许以 XML 固有的分层格式存储和查询 XML。
DB2 的 XML 支持
DB2 9 为管理、存储、查询和索引 XML 数据提供了一些新的机制。特别地,DB2 引入了:
一种 XML 数据类型,它允许 DB2 以一种经过解析的、分层的格式存储 XML 文档。
新的索引技术,这种技术能提高跨 XML 文档和在 XML 文档内进行搜索的查询的运行时性能。
基于业界标准的查询语言支持,包括 SQL 的新的 XML 扩展(通常被称作 SQL/XML)和 XQuery,后者是专为 XML 设计的。
对基于用户提供模式验证 XML 数据的支持,它可以帮助管理员为 DB2 中的 XML 数据施加完整性约束。
一些管理功能,包括对关键数据库实用程序的扩展。
Java 程序员特别感兴趣的一个新特性是 DB2 新的 Developer Workbench,它是建立在开放源代码 Eclipse 3.1 平台之上的。(请参阅 Developer Workbench 文章。)这个集成开发环境(IDE)可以帮助程序员快速开发、测试和调试他们的数据库应用程序。
对于本文中的例子,我将一直使用 DB2 Developer Workbench。当然,Java 程序员可以使用任何受支持的 IDE 或 Java Development Kit (JDK) 来创建 DB2 XML 应用程序。
设置环境
本文中的代码示例引用了一个 CLIENTS 表,该表用于跟踪关于客户的信息。清单 1 展示了这个表的定义。
注意,CLIENTS 包含三个基于传统 SQL 数据类型的列,另外还有一个基于新的名为 “XML” 的 SQL 数据类型的列。后面那个列(即 contactinfo)存储 XML 文档,这些 XML 文档包括诸如客户的邮件地址、电话号码、电子邮件地址等之类的信息。图 1 展示了一个这样的 XML 文档。
图 1. 存储在 CLIENTS 表中的示例 XML 文件
我将展示如何将该文件和其他信息插入到这个 DB2 表中。不过,首先我们还是来讨论一下如何配置 DB2 Developer Workbench。
为了使用 DB2 Developer Workbench 编译和运行 DB2 XML 应用程序,需要按照标准的 Eclipse 过程来创建一个新的 Java 项目,并将适当的 DB2 库包括在项目的构建路径中。如果您之前没有使用过 Eclipse,那么下面是对如何完成这些任务作了一个简短的概述:
启动 DB2 Developer Workbench。
创建一个新项目。切换到 Java 透视图( Window → Open Perspective → Java),并选择 File → New → PRoject。根据向导的提示指定一个项目名。对于其他项,则保留默认设置。
将 DB2 库添加到项目的构建路径中。选中您的项目,单击右键,然后选择 Properties。选择 Java Build Path,并单击 Libraries 标签页。添加适当的 DB2 外部 .jar 文件,例如 db2jcc.jar、db2jcc_javax.jar 和 db2jcc_license_cu.jar。这些文件位于 DB2 安装目录的 \java 子目录中。
还可以选择为应用程序创建一个包。选中您的项目,单击右键,然后选择 New → Package。
要查看详细信息,可以从 workbench 的主菜单中单击 Help。
连接到数据库
要使用 DB2 XML 数据,需要建立到目标数据库的连接,对于其他 DB2 应用程序也是如此。清单 2 是一个用于建立 DB2 数据库连接的助手方法的代码片段。
插入 XML 数据
DB2 程序员使用熟悉的 SQL INSERT 语句来将新的 XML 数据写到包含 XML 列的表中。DB2 可以存储最大为 2 GB 的任何格式良好的 XML 文档。
通常,Java 程序员需要将包含在文件中的 XML 数据插入到 DB2 表中,但是,他们也可以插入来自字符串、二进制数据(包括大型对象)和 SQL 子选择语句中的 XML 数据。
清单 3 展示了将一行插入到 CLIENTS 表中的方法。在这个例子中,contactinfo 列的 XML 文档是从一个文件中读取的。
我们来逐步考察这段代码。insertFile() 方法定义了一些变量,这些变量将在 INSERT 语句中用到。前三个变量对应于 CLIENTS 表中的 ID、name 和 status 这三列。第四个变量是要插入到 contactinfo 列的 XML 文件的文件名。(为简单起见,在这个例子中这些值是硬编码的。)
建立了数据库连接之后,该方法创建一个 sqlstmt 字符串,其中包含用于输入列值的四个参数占位符。然后像通常一样准备 INSERT 语句,并设置它的四个参数占位符。为了设置用于 XML 列的占位符,该方法打开一个 FileInputStream。它还计算被引用的 XML 文件的长度,并使用该信息作为 setBinaryStream() 方法的输入。最后,该方法执行 INSERT 语句,将 XML 和传统 SQL 数据插入到这个表中的一行中。
DB2 还允许用户注册 XML 模式,并且还允许用户在插入之前用这些模式来验证输入文档,不过这个特性在上述代码中没有体现出来。XML 模式是万维网联盟(W3C)业界标准的一部分;XML 模式使用户可以指定符合规范的 XML 文档应有的结构,例如可接受的 XML 元素的顺序和数据类型,特定 XML 名称空间的使用,等等。
查询 XML 数据
现在您已经将 XML 数据插入到了 DB2 中,接下来可以查询 XML 数据了。DB2 允许编写各种类型的查询。您可以编写用于检索整个 XML 文档的简单查询,也可以编写根据 XML 谓词和关系查询谓词检索 XML 文档中的某些部分的高级查询。DB2 还支持其他类型的一些查询,例如将 XML 数据转换到新的 XML 文档,连接 XML 和非 XML 数据,聚合各种类型的数据,等等。在本文中,我将演示这样一个查询:
基于关系谓词和 XML 谓词过滤数据
检索符合条件的 XML 文档的某些部分以及存储在传统 SQL 列中的数据。
DB2 目前支持两种查询语言:SQL 和 XQuery。一个应用程序可以包含用其中一种或两种语言编写的不同查询。XQuery 不支持参数占位符。实际上,这意味不需要硬编码查询谓词的 Java 应用程序中的 XQuery 查询,必须被包装在一个使用 SQL/XML 函数(例如 XMLQuery()、XMLExists() 或 XMLTable())的 SQL 语句中。本文中的示例应用程序使用 XMLQuery() 和 XMLExists() 来阐释一个常见的编程任务:检索 XML 文档的某些部分。
清单 4 中展示的例子返回居住在邮政编码为 95125 的地区的 “黄金(Gold)” 客户的姓名和首选电子邮件地址。客户姓名和状态信息(例如 “Gold” 或 “Silver”)存储在 SQL VARCHAR 列,而电子邮件地址和邮政编码则包含在存储在 contactinfo 列中的 XML 文档中。因此,这个例子同时涉及到传统 SQL 数据和 XML 数据。
对于查询变量中定义的查询语句有必要更仔细地作一番考察,特别是那些不熟悉 SQL/XML 和 XQuery 的读者更要加以注意。虽然对这些语言作彻底的讨论已超出了本文的范围,不过我们将详细分析这个查询中的每一行,使您理解它的逻辑。
第一行指定 SQL name 列和 XMLQuery() 函数的输入将被包括在结果集中。为了指示 DB2 检索第一个符合条件客户的 email 元素,代码中包括了一个 XPath 表达式。XPath 是 XQuery 的一部分,它提供了一种在 XML 文档层次之间进行导航的方式。这个 XPath 表达式指示 DB2 导航到每个符合条件的 XML 文档的 Client 根元素下的第一个 email 元素。(注意,路径表达式是大小写敏感的)。$c 变量和 SQL FROM 子句表明这些文档可以在哪里找到(在 CLIENTS 表的 contactinfo 列中)。
SQL WHERE 子句用于限制返回的数据。特别地,它规定返回的 XML 文档只包括客户状态为某个特定值(Gold)的行中的 XML 文档。而且,只有居住在某个特定地区(邮政编码为 95125)的客户的记录才符合条件。XMLExists() 函数指定后一个限制。
在这个示例查询中,XMLExists() 指示 DB2 确定一个给定的 XML 文档中是否包括指定邮政编码的客户地址。PASSING 子句指定可以在哪里找到 XML 文档(在 contactinfo 列中)。注意,这个 PASSING 子句中的 $x 周围出现了转义符(反斜杠)。这个查询的最后一行调用 CAST() 函数来将输入参数(用于邮政编码)的值强制转换为适当的 SQL 数据类型。在这个例子中,由 5 个字符组成的字符串是可以接受的。清单 5 展示了这个程序的输出。
在这个示例输出中,有一个符合条件的客户(Edward Chen)没有返回电子邮件信息。这表明他的 XML contactinfo 文档中没有包含 email 元素,可能是因为他在客户简历表中没有提供电子邮件地址。还应注意,虽然 Paula Lipenski 的联系方式信息中有两个电子邮件地址(见图 1),但是输出中只返回了她的一个电子邮件地址。这是因为示例应用程序显式地指示 DB2 只检索符合条件的客户的第一个电子邮件地址。(见 XMLQuery() 函数中的 XPath 表达式。)如果要去掉输入中的 <:email> 标记,那么可以使用 XMLQuery() 函数中的一个路径表达式来指示 DB2 只返回 email 元素的文本值 $c/Client/email[1]/text()。
编程提示
虽然 DB2 的本地 XML 支持是新的,但是良好的数据库应用程序编程实践仍然适用。例如,指示 DB2 只检索需要的数据这一点仍然很重要。如果只需要检索 XML 文档中包含的部分信息,那么检索整个 XML 文档就会降低性能,另外还会不必要地消耗一些系统资源。类似地,您应该仔细考虑事务的范围和隔离级别,在整体并发性与完整性之间取得平衡。
本文是一篇介绍性的文章,因此探索 DB2 9 的 XML 特性超出了本文的范围,但是这样做是值得的。正如您可能期望的那样,DB2 允许程序员使用熟悉的 SQL 语句更新和删除 XML 数据。此外,IBM 还在 IBM developerWorks 上发布了一个用于 XML 数据的 “update” 存储过程(“将 XML 应用程序从 DB2 8.x 迁移到 DB2 Viper,第 1 部分”;见参考资料)。这个存储过程允许用户只提供更改的 XML 数据来进行更新,而不必提供修改的 XML 文档的全部内容。
DB2 Developer Workbench 中有一些用于帮助程序员图形化地构造 SQL/XQuery 查询和 XQuery 查询的向导。它还提供了用于构建操纵传统 SQL 数据或本地 XML 数据的存储过程的向导。所有向导都可以在 workbench 的 Data 透视图中启动。
要获得关于所有这些专题的详细信息,请参阅相应的在线文档或本文后面列出的参考资料。
新鲜,但是熟悉
需要处理存储在 DB2 中的本地 XML 数据的 Java 程序员可以使用熟悉的 JDBC 语句来执行查询和处理结果。为帮助程序员编写、测试和调试他们的 Java 应用程序,IBM 提供了一个基于 Eclipse 的 Developer Workbench for DB2。这个 workbench 提供了用于查看数据库内容、用 SQL/XML 或 XQuery 编写查询以及生成存储过程的向导。