级别: 初级 C. Saracco, 高级软件工程师, IBM
2005 年 5 月 26 日 WebSphere® Information Integrator 扩展了开放源码持久性框架的应用范围,使 Java™ 程序员能够开发集成不同数据源数据的对象模型。本文介绍了如何结合使用 Hibernate 和 WebSphere Information Integrator。
简介
对于很多 Java 程序员来说,持久性仍然是一个永恒的问题。虽然过去几年中出现了多种持久存储对象的方法,但很多受到支持的数据源有限、运行时性能低下、过于复杂和维护成本太高的困扰。
为了避免或者解决其部分问题,很多 Java 程序员求助于将普通旧式 Java 对象(POJO)映射到关系数据库管理系统(RDBMS)数据的开放源码持久性框架。虽然还不清楚这类框架是否能够真正解决与持久性有关的所有那些历史问题,但是显然这种方法正引起业界越来越大的兴趣。
本文探讨了如何结合使用基于 POJO 的持久性框架和企业信息集成(EII)技术,来为程序员提供异构企业数据的集成的基于对象的视图。EII 可以扩展普及的持久性框架的数据范围,并提供新的建模能力。为了说明这些概念,本文提供了基于 Hibernate 持久性框架、Hibernator plug-in for Eclipse 和 IBM’s WebSphere Information Integrator Standard Edition 的例子。还总结了对于 Information Technology (IT) 组织而言结合使用这两种技术在什么情况下合适,并分析了程序员可能遇到的限制。
技术概述
Hibernate 是一种开放源码的、可免费下载的软件,为 Java 程序员提供了透明的持久性和对象/关系映射服务。建立表示对象的 JavaBeans 之后,Java 程序员就可以将这些 bean 映射到支持的关系 DBMS,并使用 bean 中定义的 accessor 和 mutator 方法与持久的数据交互。这样程序员就不需要在应用程序中硬编码 SQL 语句了。
本文没有提供完整的 Hibernate 的教程,请访问
Hibernate Web 站点 或者阅读相关的
developerWorks 文章。
对于不同的、分散的企业数据源,包括 XML 文件、Web 服务输出、消息队列数据、RDBMS 和扁平文件等,WebSphere Information Integrator Standard 和 Advanced Editions 为程序员提供了一个统一的视图。WebSphere Information Integrator Classic Federation 是一种基于主机的联邦数据服务器,可以单独使用,也可以和 WebSphere Information Integrator Standard 或 Advanced Editions 结合集成来自主流主机数据源的数据,如 IMS、VSAM、Datacom/DB、Adabas 和 IDMS。
为了向程序员提供虚拟的数据库界面,WebSphere Information Integrator 管理员使用向导或者示例 SQL 脚本创建了几个联合的数据库对象,其中包括:
- 针对将要访问的每种数据源类型的
包装器 定义。比如要访问三个 Oracle DBMS 实例和一个 Teradata 实例,需要定义两个包装器分别用于 Oracle 和 Teradata。
- 与每个包装器关联的
服务器 对象,给出了目标数据的位置,如主机或 TCP/IP 名。
- 每个服务器对象的
用户映射。在多数生产环境中,用户映射将 WebSphere Information Integrator 用户 ID 和口令翻译成有效的远程数据源帐户。
-
别名 用于识别每台服务器上所涉及的数据集合(如表、视图、文件)。
要注意,Hibernate 只是可用于 WebSphere Information Integrator 的持久性方法中的一种。关于如何结合使用 WebSphere Information Integrator 和实体 Enterprise JavaBean 以及 Service Data Object,请参阅本文
参考资料 中的链接。
软件配置
本文后面部分所述的开发场景使用了以下软件:
-
IBM WebSphere Information Integrator Standard Edition V8.2.
-
Hibernate 2 和 Hibernator Eclipse 插件 0.9.6 版,可以
免费下载。
-
Eclipse 3.0.1 集成 Java 开发环境,可
免费下载。注意,Hibernator 插件也可在基于 Eclipse 2.0 的平台上使用。(WebSphere Studio Application Developer 以 Eclipse 2 为基础,而 Rational Application Developer 则基于 Eclipse 3。 因此 Hibernator 可用于这两种产品。)
多个数据源的 Hibernate 应用场景
为了说明 Hibernate 和 WebSphere Information Integrator 的用法,本文给出了一个详尽的开发例子,涉及到三种类型的持久对象,其中两种位于远程 Oracle 数据库中,另一种保存在本地 XML 文件中。因为 WebSphere Information Integrator 支持多种不同的数据源,包括非 Hibernate 原生支持的很多种数据源,因此本文所述的开发场景也适用于很多其他数据源。另外,本文所使用的模式(schema)包括产品对象的部分层次结构(这种结构可以在数据仓库的星形模式中找到)和客户对某些产品的注释(存放在 XML 文件中)。
注意,这一开发场景需要使用 Hibernate 将已有持久性数据表示成基于对象的视图。与很多持久性框架一样,Hibernate 也可用于创建新的对象模型和持久存储到新的关系表中。事实上,按照这一思想已经写出了一些
Hibernate 教程。
但是在很多 IT 项目中,开发人员不可能从一张白纸开始。实际上,Java 开发人员常常需要构建应用程序和组件来处理已有的企业数据。这个练习就是按照这种目标设计的。它还探讨了当重要的企业数据存储在不同数据源时 Java 程序员如何使用 Hibernate 的问题。
像通常那样安装和配置 WebSphere Information Integrator 之后,使用 Hibernate 对象还需要:
第 1 步:建立 Eclipse 环境
像通常那样安装 Eclipse 之后按照以下步骤设置环境:
- 根据需要,解压 Hibernator 插件到 Eclipse 主安装目录,并重新启动 Eclipse。
- 在 Eclipse 中创建一个 Java 项目。在项目的构建路径中导入适当的 Hibernate 库和 WebSphere II JDBC 驱动程序库。如
图 1 所示,当然不同的应用程序要求可能有不同的设置。
- 验证 Hibernator 是否正常:
- 打开 Hibernator 透视图。
Window-> Open Perspective -> Other -> Hibernator。
- 右击 Connection View 窗格,添加一个新连接并指定关联的 Java 项目。
- 填写连接信息,指定 DB2 作为 Dialect。使用 DB2 基于 CLI 的 JDBC 驱动程序的例子如
图 2 所示。
- 在 Connection View 面板中选择并右击连接,连接到数据源。
- 在 Results View 窗格中,查看 Hibernator Log,检查是否出现连接错误。
- 如果熟悉 Hibernate Query Language 而且愿意的话,也可在 Query View 中执行查询。
图 1. 包含在项目类路径中的示例文件
图 2. 示例连接信息
第 2 步:创建属性文件
让 Hibernate 和 WebSphere Information Integrator 通信,最简单的办法是在项目中添加一个 hibernate.properties 文件。以后当 Hibernate 客户应用程序创建“session”包装 JDBC 连接时,Hibernate 将查询该文件并透明地连接到指定的数据库。
使用文本编辑器创建一个文件,规定应用程序需要的属性。
图 3 给出了一个例子,为 WebSphere Information Integrator 连接定义了 JDBC 属性(也规定了要使用 DB2 Universal JDBC 驱动程序)。
图 3. 示例属性文件
第 3 步:创建 JavaBeans
如前所述,Hibernate 使用 POJO(普通旧式 Java 对象)表示持久的数据。具体而言,这些对象需要实现为简单的 JavaBean,每个属性都有 accessor 和 mutator 方法(“getter”和“setters”)。如果需要,还可以将这些方法或者其中的一部分设置为私有以限制其使用。事实上,使用 WebSphere Information Integrator 访问非关系数据时,这是一个重要的预防措施。这类数据源是只读的,因此应该将其 mutator 方法设为私有,以减少运行时错误。如果类定义中简单地省略 mutator 方法,则不仅违反了 JavaBeans 的编程惯例,而且会造成 Hibernate 失败。
要为持久数据创建 JavaBeans,按照标准的 Eclipse 过程定义一个新类,包括必要的属性。如果需要,可以直接要求 Eclipse 生成 getter 和 setter 方法。只要选中创建的类,右击鼠标,然后选择
Source -> Generate Getter and Setter -> All 即可。
为了便于掌握后面的例子,下面给出了三个 JavaBean 的代码片段。Product 和 ProductClass 对象由 Oracle 数据库管理,表示某家公司销售产品的信息和每个产品的类型(分类)。这些信息表示零售商用于联机分析处理需求的信息的一个子集。Comment 对象记录在 XML 文件中,表示客户向零售商支持中心提出的反馈意见或请求。
要注意这些对象是互相联系的。就是说,ProductClass 的定义包含一组 Product,Product 的定义则包含一组 Comment。在实践中,这些关系是通过连接(join)操作动态建立的。这是将对象模型映射到关系数据库模型的一种典型框架。
清单 1: Product
package myfed;
import java.math.BigDecimal;
import java.util.Set;
public class Product {
// attributes – each map to a column in a WebSphere II nickname
private int productClassID;
private int productID;
private String brandName;
private String productName;
private Double SKU;
private BigDecimal SRP;
// at runtime, the contents of this set will be generated
// by a join of Product and Comment nicknames
private Set commentSet;
// getter and setter for one attribute
public String getBrandName() {
return brandName;
] }
public int getProductClassID() {
return productClassID;
}
// other getters and setters follow
. . .
}
|
清单 2: ProductClass
package myfed;
import java.util.Set;
public class ProductClass {
// attributes – each map to a column in a WebSphere II nickname
private int productClassID;
private String productSubCategory;
private String productCategory;
private String productDepartment;
private String productFamily;
// at runtime, the contents of this set will be generated
// by a join of Product and ProductClass nicknames
private Set productSet;
// getters and setters follow
. . .
}
|
清单 3: Comment
package myfed;
public class Comment {
// attributes – each map to a column in a WebSphere II nickname
private int commentID;
private int productID;
private int customerID;
private String message;
private String responseRequested;
// getters and setters follow
. . .
}
|
第 4 步:创建 Hibernate 映射
创建 JavaBean 之后,接下来要定义这些对象和持久数据存储之间的 Hibernate 映射。在这里,映射引用 WebSphere Information Integrator 中的别名。其中两个别名和远程 Oracle 表联系,一个和本地 XML 文件联系,不过这些信息对 Hibernate 程序员是隐藏的。相反,程序员只需要将这些 WebSphere Information Integrator 别名看作是兼容 DB2 的表。
可以使用 Hibernator 生成每个 JavaBean 所需映射文件的一部分:
- 在编辑器中打开 JavaBean 的 .java 文件。
- 单击
Window -> Show View -> Other -> Hibernator -> Hibernator。
- 右击 Hibernator 视图选择
Save 初始映射,可以在工作区中看到 .hbm.xml。
生成的映射文件需要进一步定制。有很多选项可以使用,在 Hibernate 参考手册中有详细的说明,这里不再介绍。不过,
图 4、
图 5 和
图 6 提供了映射上述 JavaBean 的 XML 源代码。在分析这些清单之前,还有几点需要注意:
- “schema”属性指的是数据库模式名。本文中的例子指的是与由 WebSphere Information Integrator 统一管理的两个不同模式相关联的对象。
- “table”属性实际上指的是别名(远程数据对象)。如果需要也可使用视图。
- 所有 Hibernator 对象都需要主键,通过“id”属性指定。
- 对象之间的关系,比如涉及关系 DBMS 中的主键/外键连接的关系,可使用“set”属性建模。本文使用的对象模型包括两个这样的组(set)。Product 对象有一组相关的 Comment,ProductClass 对象有一组相关的 Product。
图 4. Product 对象的 Hibernate 映射
图 5. ProductClass 对象的 Hibernate 映射
图 6. Comment 对象的 Hibernate 映射
第 5 步:创建测试应用程序
创建必要的 JavaBean 并定义了这些对象与 WebSphere Information Integrator 别名或视图的 Hibernate 映射之后,最后一步是编写一个测试应用程序来使用 Hibernate API。当然,应用程序中包含的逻辑取决于要测试的功能。
下面的清单通过 WebSphere Information Integrator 使用 Hibernate API 访问 Oracle 表和 XML 文件中的数据。程序首先初始化 Hibernate 环境并打开一个 Session,后者包装了到联邦数据库的 JDBC 连接。该 Session 使用前面定义的属性文件确定适当的目标数据库、用户信息,等等。
测试应用程序的后面两部分发出两个不同的查询。第一个检索特定品牌的 Product 信息;这些信息都保存在一个 Oracle 表中。第二个检索 Product 和所有相关用户建议的信息。这些信息分别来自 Oracle 表和 XML 文件,但是应用程序并不知道这一点。事实上,这里使用对象模型(一组 Comment 与 Product 关联)之所以成为可能,部分原因在于 WebSphere Information Integrator 能够提供分散的、不同数据源的虚拟数据库视图。
清单 4: 测试应用程序
package myfed;
// import required packages
import net.sf.hibernate.cfg.Configuration;
. . .
// begin class definition
public class ClientProductView {
// define variables for JavaBeans and Hibernate objects
private static Session session = null;
private Product product = null;
private ProductClass productClass = null;
private static SessionFactory sessionFactory = null;
private static Transaction tx = null;
private static List result = null;
public static void main(String[] args) {
. . .
try {
// initialize Hibernate
sessionFactory = new Configuration()
.addClass(Product.class)
.addClass(ProductClass.class)
.addClass(Comment.class)
.buildSessionFactory();
System.out.println("Built session factory.");
// open a session
session = sessionFactory.openSession();
System.out.println("Session opened.");
// Retrieve a collection of products meeting our criteria
String value = new String("Elegance");
tx = session.beginTransaction();
System.out.println("Transaction opened.");
Query q = session.createQuery("from Product p " +
" where p.brandName = :value");
System.out.println("Created query.");
q.setParameter("value", value);
int max = 10;
q.setMaxResults(max);
System.out.println("Set parameter marker.");
result = q.list();
// print list of qualifying products
for (int i = 0; i < max; i++) {
Product p = (Product) q.list().get(i);
System.out.println("Product name: " +
p.getProductName() +
" Brand name: " + p.getBrandName());
}
// Illustrate join processing across multiple sources
Integer prodID = new Integer(4023);
q = session.createQuery("from Product p " +
" where p.productID = :value");
System.out.println("Created query.");
q.setParameter("value", prodID);
System.out.println("Set parameter marker.");
result = q.list();
System.out.println ("Found object: " + result.get(0));
Product p = (Product) q.list().get(0);
System.out.println("Product name: " + p.getProductName() +
" Suggested retail price: " + p.getSRP());
Set commentSet = p.getCommentSet();
System.out.println("Here's what customers are saying . . . . ");
Iterator i = commentSet.iterator();
while (i.hasNext()) {
Comment comment = (Comment) i.next();
System.out.println("Customer ID: " +
comment.getCustomerID() +
" Message: " + comment.getMessage());
}
tx.commit();
System.out.println("Transaction completed.");
}
catch (Exception e) {
. . .
}
finally {
try {
if (tx != null) { tx.rollback(); }
if (session != null){ session.close(); }
}
catch (Exception e) { // ignore }
}
}
} // end main
}
|
运行该应用程序将产生简单的线性输出,包括一些状态说明可用于跟踪程序的执行,如清单 5 所示。当然,这种输出并不适合生产应用程序,但确实有助于您理解测试应用程序的逻辑。
清单 5: 测试应用程序的输出结果
Built session factory.
Session opened.
Transaction opened.
Created query.
Set parameter marker.
Product name: Cashmere Dress 1 Brand name: Elegance
Product name: High Heels 6 Brand name: Elegance
Product name: Wool Dress 2 Brand name: Elegance
Product name: Cashmere Dress 2 Brand name: Elegance
Product name: Cardigans 1 Brand name: Elegance
Product name: Wool Dress 5 Brand name: Elegance
Product name: Blazer 2 Brand name: Elegance
Product name: Wool Dress 1 Brand name: Elegance
Product name: High Heels 3 Brand name: Elegance
Product name: High Heels 9 Brand name: Elegance
Created query.
Set parameter marker.
Found object: myfed.Product@1855562
Product name: Back Packs Suggested retail price: 34.2600
Here's what customers are saying . . . .
Customer ID: 9711 Message: Customer wants to know if this product can
be special order
Customer ID: 4309 Message: Buckle broke after only 3 months of use. Refund requested.
Transaction completed.
|
优点和局限性
现在已经看到了如何结合使用 WebSphere Information Integrator 和 Hibernate(以及其他面向对象的持久性方法),考虑一下这样做的优点和局限性非常必要。
WebSphere Information Integrator 将 Hibernate 的应用范围扩展到其本身不支持的数据源。按照 Hibernate 项目网站的介绍,它正式支持九种不同数据源的多个版本,还有其他几种数据源经过测试,被认为与 Hibernate 兼容。WebSphere Information Integrator 支持更多的数据源,包括 Teradata、几种主机数据源、文件系统、第三方应用程序、消息队列和 Web 服务。通过建立和经过适当配置的 WebSphere Information Integrator 数据库的 Hibernate 会话,这些数据源(还有其他一些)就能够从 Hibernate 应用程序访问。
此外,WebSphere Information Integrator 创建的虚拟数据库视图使 Hibernate 程序员能够更方便地创建跨越企业中多种分布式数据源的对象模型。如本文中的例子那样,两个互相联系的 JavaBean 可以映射到不同系统上的不同数据源,同时又能通过一个 Session 对象(或者一个 JDBC 连接)来访问。这样就降低了编码的复杂性,为程序员提供了更加集成化的分布式数据视图。
那么有什么问题呢?最大的问题可能是 WebSphere Information Integrator 仅提供了某些数据源的只读访问。比如 XML 文件和其他主机之外的非关系数据源都是只读的。因此,Hibernate 程序员可以建立这些数据的基于对象的模型,通过典型的“getter”访问这些数据,但是不能通过“setter”方法修改数据。另外,无法在单个事务中更新多个关系数据源,这是因为 WebSphere Information Integrator 的当前版本不支持跨越多个关系 DBMS 的两阶段提交过程。
参考资料
关于作者  | |  | Cynthia M. Saracco 在IBM 硅谷实验室从事数据库管理和 Web 应用程序开发方面的工作。 |
对本文的评价
|