如果您厌烦了编写 JDBC,可以考虑使用另一个功能丰富的数据映射框架 iBatis,它能够实现大多数同样的好处,并且只需要编写非常少的代码。
引言
对象关系映射程序(Object Relational Mappers,ORM)有多种形式。在 Java™ 中,大多数流行的 ORM 都可以实现完整的域模型映射,它的目标是将整层的对象和行为映射到数据库表。流行的 ORM 包括:
  • Hibernate
  • JDO
  • EJB Entities 3
  • EJB Entity Beans 2.x
  • TopLink
上 面每一个框架都被分类为一个完整的域模型映射程序,其中将表映射到对象,对象状态得到维护,对象在任何时间或者某些时间跟随一个连接的模型(由于客户机组 件与对象交互,因此将涉及到基础数据库操作),并且抽象查询语言通过对象模型进行工作。反过来,这些框架将生成 JDBC 或隐藏的 SQL 代码。
然而,在某些情况下,您可能决定改为直接使用 JDBC。原因可能是:
  • 开发人员对 SQL 的了解以及使用 SQL 是否得心应手。对象查询语言仍不能免除必须了解 SQL,这是因为通常需要了解如何调优查询语言。
  • 对象关系映射程序对于某些类型的应用程序是重量级的。例如,必须连续执行多个更新操作的批处理应用程序通常能够更好地依次执行 SQL 语句,而无需所有额外的对象交互。
  • 存储过程是必需的或者已经存在。使用存储过程有多种合理的理由。在某些场景中,它们可以减少网络 IO 的数量,因为 SQL 语句可以在数据库依次执行。
  • 数据库管理员具有权限。许多开发组织对于 SQL 以及可以定义 SQL 的人员有严格的规定。有时,只有数据库管理员有权创建 SQL 并对 SQL 的性能进行调优。
  • 以前的环境。例如,正在从已经调优并测试 SQL 查询的平台上迁移应用程序。
对 于上述情况,通常的解决方案可能是:使用 JDBC。在构建 JDBC 代码时开发人员常常需要一些指导;差的 JDBC 代码往往使得到处都是数据访问代码。为了实现其所需的功能,开发人员最终常常开发某种自定义 JDBC 框架或者包装。这可能发生在以下情况中,例如:
  1. 应用程序正在运行于 J2EE™ 平台。Java 对象仍需要作为数据传输对象从业务逻辑层传递到视图层,因此需要一些代码将结果集数据移到数据传输对象,然后从数据传输对象移到 SQL 更新、插入或者删除。
  2. 应用程序仍需要抽象层。只是因为某人使用了 JDBC,它不能免除必须正确地对代码分层。
  3. 应用程序需要将 SQL 从 Java 代码提取出来以进行调优。
  4. 冗余是不可避免的。在编写 JDBC 时,开发人员常常发现自己在一次又一次地编写相同的普通代码,如获得连接、准备语句、循环结果集以及其他一些 JDBC 特定元素。
好消息
这里有一个对象关系映射程序,它是一块隐藏的宝石。它没有创建完整的域模型,其工作是将 Java 对象直接映射到 SQL 语句。这个框架称为 iBatis,它的目标是实现百分之八十的 JDBC 规范代码,否则您必须自己编写这些代码。此外,它还提供了一个简单的映射和 API 层,使开发人员能够快速地开发数据访问代码。
iBatis 是什么?
iBatis 是一个开源的对象关系映射程序,其工作是将对象映射到 SQL 语句。通过使用一个称为 SQL 映射的简单概念,实现将 Java 对象(如下所示)映射到 SQL 语句:
public class Customer implements Serializable {

private String name;
private int customerId;
private CustomerOrder customerOrder;

public Customer()
{
System.out.println("Creating CustomerBO...");
}
/**
* @return Returns the customerId.
*/
public int getCustomerId() {
return customerId;
}
/**
* @param customerId The customerId to set.
*/
public void setCustomerId(int customerId) {
this.customerId = customerId;
}
/**
* @return Returns the name.
*/
public String getName() {
return name;
}
/**
* @param name The name to set.
*/
public void setName(String name) {
this.name = name;
}


/**
* @return Returns the customerOrder.
*/
public CustomerOrder getCustomerOrder()
{
return customerOrder;
}
/**
* @param customerOrder The customerOrder to set.
*/
public void setCustomerOrder(CustomerOrder customerOrder)
{
this.customerOrder = customerOrder;
}
}

您需要在名为 SQLMap 的文件内定义该映射。示例如下:
<sqlMap namespace="Customer">
<parameterMap id="updateCustomerOrderParamMap"
class="com.ibm.ibatis.sample.bo.CustomerOrder">
<parameter property="orderId" />
<parameter property="customerId" />
</parameterMap>

<resultMap
class="com.ibm.persistence.ibatis.bo.Customer"
id="customerOrderMap">
<result property="customerId"
column="CUST_ID"
nullValue="0" />
<result property="customerOrder.orderId"
column="OPEN_ORDER_ID"
nullValue="0" />
<result property="customerOrder.customerId"
column="CUST_ID"
nullValue="0" />
</resultMap>
<statement id="checkCustomer"
parameterClass="java.lang.Integer"
resultMap="customerOrderMap">
SELECT CUST_ID, OPEN_ORDER_ID FROM CUSTOMER_USER.CUSTOMER WHERE CUST_ID = #customerId# FOR UPDATE
</statement>
<statement id="getOrderId"
parameterClass="java.lang.Integer"
resultClass="java.lang.Integer">
SELECT ORDER_ID FROM CUSTOMER_USER.ORDER WHERE CUSTOMER_ID = #customerId# AND STATUS='OPEN'
</statement>
<statement id="insertOrder"
parameterClass="java.lang.Integer">
INSERT INTO CUSTOMER_USER.ORDER (STATUS, TOTAL, CUSTOMER_ID)VALUES('OPEN',0,#customerId#)
</statement>
<statement id="updateCustomerOrderId"
parameterMap="updateCustomerOrderParamMap">
UPDATE CUSTOMER_USER.CUSTOMER SET OPEN_ORDER_ID = ? WHERE CUST_ID = ?
</statement>
</sqlMap>

iBatis 将参数映射定义为语句的输入,并且将结果映射定义为映射 SQL ResultSets。这些映射被分配到可以执行的语句。应用程序可以与 iBatis API 交互以执行 SQL 操作,如下所示:
//Access SQL client Maop
SqlMapClient sqlMapClient = OrderEntryConfig.getSqlMapInstance();

//1. Retrieve total using SUM() function in SQL
Integer total = (Integer)sqlMapClient.queryForObject("getOrderTotal",new Integer
(customerOrder.getOrderId()));
//2. Set total in CustomerOrder Object
customerOrder.setTotal(total);
//3. Update Total column in DB
sqlMapClient.update("updateOrderTotal",customerOrder);

如您所见,执行 SQL 语句决不是一件简单的事情。iBatis 支持所有 JDBC 应用程序需要的大多数功能:
  • JDBC 事务界定,包括对委托给 JDBC 事务 API、EJB 容器中的容器托管事务或者 JTA 事务中的用户事务对象的支持。
  • 覆盖缺省数据类型映射和创建自定义类型映射程序的功能。
  • 到复杂对象图的复杂连接的映射,包括多种 Java 集合类型。
  • 将数据加载到 HashMaps 的功能(在查询时列名是未知的)。
  • 对象图 lazy loading。
  • JDBC 批处理语句。
  • 映射到存储过程。
  • 动态的 SQL 映射,其中 SQL 语句可以构造为基于 JavaBean 的状态。
  • 缓存结果和委托给其他缓存机制(如 IBM WebSphere® Application Server 动态缓存)的功能。
  • 新增的 DAO 框架;iBatis 提供了在数据映射程序中可以选择使用的 DAO 模式的完整实现。
虽然 iBatis 还支持许多其他功能,但是它不能与成熟完备的 ORM 相比,ORM 具有抽象的查询语言,能够将 OO 构造(如继承)映射到复杂的表关系,或者具有完全托管的对象状态。iBatis 只是使您能够将数据直接从 SQL 移到简单的断开连接的对象。
本文旨在让喜欢自己编写 SQL 的开发人员知道 iBatis 是一个非常强大且功能丰富的 ORM。下面提供了详细的参考资料信息。
如果您确定不需要使用完备的 ORM 并且倾向使用 JDBC,则可以考虑改用 iBatis。您几乎能够获得 JDBC 的全部好处(而无需编写过多的代码),并且还可以获得分层的体系结构以及重用已经调优的 SQL 查询的功能。


参考资料
  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文

  • iBatis 项目站点

  • IBatis 下载资料和文档

  • DB2 UDB、WebSphere 和 iBATIS

  • IBM WebSphere: Deployment and Advanced Configuration

  • Patterns of Enterprise Architecture


关于作者
照片:Roland
Roland Barcia 是位于纽约/新泽西地区的 IBM Software Services for WebSphere 的一名 IT 咨询专家。他还是 IBM WebSphere: Deployment and Advanced Configuration 一书的合著者。有关 Roland 的更多信息,请访问他的网站