级别: 初级
Uwe Weber
Informix 和 DB2 UDB 的 IT 专家, IBM Germany
2005 年 6 月 30 日
如果您正在使用 Java™ 开发数据库应用程序,并在寻找用于实现跨数据库的分布式事务解决方案,那么您应该评估一下 Java Transaction API(JTA)。本文将向您介绍分布式事务,以及如何在 Java 中使用 JTA 处理它们 —— 具体来说是在使用 DB2® UDB 或 Informix® Dynamic Server 的时候。
简介
在现代企业环境中,用多个数据库和多种品牌的数据库来存储公司数据已经不足为奇。最终,这些数据将会在不同数据库外进行比较、合并。
如果您有一个异构的数据库环境,并且计划将不同数据库中的数据收集到一个单独的应用程序中,那么您就应该可以使用传统技术执行该任务。在使用 Java 时,您将通过 JDBC 处理所有的数据库操作。清单 1 展示了在 Java 应用程序中如何连接 DB2 UDB 和 IDS 的代码片断。
清单 1. 使用 JDBC 建立到不同数据库的连接
1 try { // load JDBC drivers
2 Class.forName (JDBC_DRIVER_DB2);
3 Class.forName (JDBC_DRIVER_IDS);
4 }
5 catch (Exception e) {
6 // error handling
7 }
8
9 try { // establish connection and proceed with operation
10 con_db2 = DriverManager.getConnection (DBURL_DB2);
11 con_ids = Drivermanager.getConnection (DBURL_IDS);
12
13 Statement stmt_db2 = con_db2.createStatement ();
14 Statement stmt_ids = con_ids.createStatement ();
15
16 ResultSet rs_db2 = stmt_db2.executeQuery (SQL);
17 ResultSet rs_ids = stmt_ids.executeQuery (SQL);
18
19 // do something very important with the result sets...
20 }
21 catch (SQLException e) {
22 // error handling
23 }
两阶段提交协议简介
清单 1 中的演示允许您修改不同数据库中的数据。代替执行查询,它可以使用 JDBC 方法 executeUpdate() 执行数据修改。
但是如果您需要在单个事务中封装到 DB2 和 IDS 表的新一行的 insert ,要做什么呢? 意思就是说,如果其中一条 insert 语句失败了,就应该将数据库(这里:两种数据库!)的初始状态恢复为客户机未执行任何动作的状态。该行为可以通过使用两阶段提交(Two-Phase-Commit)协议完成。这一标准化协议描述了如何实现分布式事务(XA)或分布式工作单元(Distributed Unit of Work,DUOW)的技术,以达到跨数据库系统的一致状态(根据 ACID)。
常规事务(单阶段提交)中,由 COMMIT 或 ROLLBACK 所执行的事务终止是一种决定性的操作,与之相反,两阶段提交(Two-Phase-Commit)事务是分为两步(阶段)进行的。
首先,两阶段提交(Two-Phase-Commit)事务的启动与常规的单阶段提交(One-Phase-Commit)事务类似。接着,应用程序/客户机对该两阶段提交(Two-Phase-Commit)操作中所涉及的所有数据库执行其修改工作。现在,在最终提交该事务之前,客户机通知参与的数据库准备提交(第 1 阶段)。如果客户机从数据库收到一条“okay”,就发出命令向数据库提交该事务(第 2 阶段)。最后分布式事务(Distributed Transaction)结束。
两阶段提交(Two-Phase-Commit)中的第 1 阶段十分重要。通过首先询问数据库是否可以进行提交,一旦某一参与的数据库报告错误,就有机会立即中止整个事务。因而,第 2 阶段将由 ROLLBACK ,而非 COMMIT 完成。
图 1 提供了对于两阶段提交(Two-Phase-Commit)协议如何工作的图形化印象。正如所演示的,分布式事务(Distributed Transaction)使用由元组表示的描述符(例如:[x,b1])。其意思是,一个分布式事务(Distributed Transaction)包含两个元素。首先,有一个惟一全局事务 ID(global transaction id) —— 代表分布式事务(Distributed Transaction)的简单标识符 - 由 x 表示,第二个是分支 ID(branch id),它描述整个事务的一部分。一般,分支指的是一个数据库连接。如果您有一个将处理两个参与数据库的分布式事务(Distributed Transaction),您就可以用诸如 [100,1] 的描述符表示一个数据库,用诸如 [100,2] 的描述符表示另一数据库。因此本例中,就有一个编号为 100 的全局事务,其中包含两个 ID 分别为 1 和 2 的分支。
“但是”,您或许会问,“如果在两阶段提交(Two-Phase-Commit)协议的第 2 阶段中出现错误,又将发生什么事情呢?” “的确,您将陷入麻烦中!” 实际上,稍后我们将会讨论该主题。
图 1. 两阶段提交中的时间线和应用程序流
请看 清单 2。在第 16-19 行代码中,您可能错觉地认为第 17 和 18 行的语句都是属于由 con_db2.setAutoCommit(false) (第 16 行)所定义的事务边界的一部分。而事实却是该行代码启动了一个显式事务,用于连接到由 con_db2.commit() (第 19 行)所提交的 DB2 数据库。第 18 行中所做的修改不受该事务的影响。本例没有使用两阶段提交(Two-Phase-Commit)协议,因此,它不是一个分布式事务(Distributed Transaction)。无论是到 DB2 数据库的连接,还是到 Informix Dynamic Server(IDS)的连接,它们都没有意识到彼此的存在。
清单 2. 非“两阶段提交”的应用程序
1 try {
2 Class.forName (JDBC_DRIVER_DB2);
3 Class.forName (JDBC_DRIVER_IDS);
4 }
5 catch (Exception e) {
6 // error handling
7 }
8
9 try {
10 con_db2 = DriverManager.getConnection (DBURL_DB2);
11 con_ids = Drivermanager.getConnection (DBURL_IDS);
12
13 Statement stmt_db2 = con_db2.createStatement ();
14 Statement stmt_ids = con_ids.createStatement ();
15
16 con_db2.setAutoCommit (false);
17 stmt_db2.executeUpdate (SQL);
18 stmt_ids.executeUpdate (SQL);
19 con_db2.commit ();
20
21 // further processing
22 }
23 catch (SQLException e) {
24 // error handling
25 }
JTA 和事务管理器(TM)
Java Transaction API 允许您操作应用程序中的分布式事务(Distributed Transaction)。JTA 中有一组方法,它将传统的 JDBC 调用封装到了两阶段提交(Two-Phase-Commit)协议中。
在异构环境中,您通常会发现一个事务管理器(Transaction Manager),负责处理分布式事务。(实际上,事务管理器可以完成大量的工作负载平衡。)因此,不仅存在到数据库的直接连接,还有到事务管理器(Transaction Manager)的连接。这就是 JTA 发挥作用的地方:JTA 是 Java 应用程序和事务管理器(Transaction Manager)之间的接口。图 2 演示了一个包含分布式事务的典型环境。
由于存在事务管理器(Transaction Manager),它通常包含在应用程序服务器(Application Server)中,就不再有两层(Two-Tier)架构。传统的客户/服务器(Client/Server)架构已经由三层(Tree-Tier)架构所取代,三层架构包含应用程序/客户机、事务管理器(Transaction Manager)/应用程序服务器(Application Server)和数据库服务器,而数据库服务器一般称作 XA Resource。
图 2. 三层架构
- 包含 SQL 和 JTA 调用的 Java 应用程序。
- 管理分布式事务的应用程序服务器(Application Server)。
- 参与分布式事务的数据库。
- Java 应用程序向应用程序服务器(Application Server)提交常规 SQL 语句和通用的 XA 调用。
- 应用程序所发送的消息由应用程序服务器(Application Server)进行处理,并使用 SQL 和数据库供应商特定的 XA 调用发送给数据库。
通常,应用程序服务器(Application Server)提供了应用程序可以使用的多种服务。在谈到分布式事务时,该服务就称作 XA Resource。当然,在应用程序可以使用 XA Resource 之前,首先要在应用程序服务器中注册和配置 XA Resource。
现在,如果您计划在应用程序中使用 JTA,就必须修改代码,以便还可以与应用程序服务器(Application Server)进行通信。这包括一些附加的方法调用和指定的错误/异常处理。请参阅 清单 3,以了解如何工作。
用 JTA 进行两阶段提交的必要条件
首先,在编写 JTA 应用程序时,您需要合适的 JDK。好消息就是在使用当前的 JDK 时,不需要任何附加包。(JTA 包也可以在 Sun Developer Network 上找到。)大多数的 JTA 相关类都在 javax.transaction 和 javax.transaction.xa 中。
您需要用于 DB2 UDB 和 Informix Dynamic Server 的 JDBC 驱动程序。您将需要 Type 4 JDBC 用于 Informix Dynamic Server。DB2 要求您来选择需要哪个 JDBC 驱动程序。有 Type 2、3 和 4 JDBC。在用 JTA 进行编程时,您必须使用 Type 2 或 4 JDBC 驱动程序。为了方便,本文中所演示的所有例子都使用 Type 4 JDBC 驱动程序用于 DB2。(关于各驱动程序之间差别的解释,请查阅手册。)
以上描述说明了应用程序服务器(Application Server)或事务管理器(Transaction Manager)的存在。在下面的例子中,您不会看到“外部”应用程序服务器(Application Server),因为已经使用 DB2XADataSource 和 IfxXADataSource 类直接将之构建到您的应用程序中了。如果您使用一个真正的应用程序服务器(Application Server),那么该应用程序服务器将使用这些类来连接到数据库的本地 XA 调用。
下面的例子(清单 3)演示了一个小型应用程序,该应用程序使用 JTA 实现两阶段提交(Two-Phase-Commit)协议。该例子并不完整,是为了让代码更加易读。请参阅 下载 部分,以获得完整代码。
清单 3. 两阶段提交的应用程序
19 import java.io.BufferedReader;
20 import java.io.FileInputStream;
21 import java.io.IOException;
22 import java.io.InputStreamReader;
23
24 import java.sql.Connection;
25 import java.sql.SQLException;
26 import java.sql.Statement;
27
28 import java.util.Properties;
29
30 import javax.sql.XAConnection;
31 import javax.transaction.xa.XAException;
32 import javax.transaction.xa.XAResource;
33 import javax.transaction.xa.Xid;
34
35 import com.ibm.db2.jcc.DB2XADataSource;
36 import com.ibm.db2.jcc.DB2Xid;
37
38 import com.informix.jdbcx.IfxXADataSource;
39 import com.informix.jdbcx.IfxXid;
在第 19-39 行中,您看到了该应用程序中所使用的所有类。大多数类是您所知道的。第 30-33 行中导入的类是使用 JTA 所必要的。同样有意思的是第 35、36 和 38、39 行中的数据库供应商的特定类。xyzXADataSource 类包含了用于启用两阶段提交协议的本地 XA 代码。
44 class DBX {
45
46 private Properties props;
47 private String propertyfile = "jtadb2ifmx.properties";
[1] [2] [3] 下一页 [聊天工具]企业邮件系统的利器----FoxMail Server [系统软件]OPEN SERVER 5.0.5安装EXP300阵列柜 [系统软件]关于Windows2000Server的灾难恢复 [常用软件][网络]下载服务革命性风暴Poco Server评测 [C语言系列]动态创建SQL Server数据库、表、存储过程等架构信… [C语言系列]SQL Server到DB2连接服务器的实现 [C语言系列]SQL Server到SYBASE连接服务器的实现 [C语言系列]SQL Server到SQLBASE连接服务器的实现 [C语言系列]SQL Server连接VFP数据库的实现 [C语言系列]ASP+SQL Server之图象数据处理
|