Welcome 微信登录

首页 / 软件开发 / JAVA / Java理论与实践: 理解JTS —— 事务简介

Java理论与实践: 理解JTS —— 事务简介2010-12-22 IBM Brian GoetzJava Transaction Service 是 J2EE 架构的关键元素。它与 Java Transaction API 结合在一起,使我们能够构建对于各种系统和网络故障都非常 健壮的分布式应用程序。事务是可靠应用程序的基本构建块 —— 如果没有事务 的支持,编写可靠的分布式应用程序将是非常困难的。幸运的是,JTS 执行的大 部分工作对于程序员都是透明的;J2EE 容器使事务划分和资源征用对程序员来 说几乎是不可见的。这个由三个部分组成的系列文章的第一期讲述了一些基础知 识,包括什么是事务,以及事务对于构建可靠的分布式应用程序来说至关重要的 原因。

如果您阅读过任何有关 J2EE 的介绍性文章或者书籍,那么就会发现,只有 一小部分资料是专门针对 Java Transaction Service(JTS)或 Java Transaction API(JTA)的。这并不是因为 JTS 是 J2EE 中不重要的部分或者 可选部分 —— 恰恰相反。JTS 受到的关注之所以会比 EJB 技术少,是因为它 为应用程序提供的服务非常透明 —— 很多开发人员甚至没有注意到在他们的应 用程序中事务在哪里开始和结束。在某种意义上,JTS 的默默无闻恰恰是它的成 功:因为它非常有效地隐藏了事务管理的很多细节,因此,我们没有听说过或者 谈论过很多关于它的内容。但是,您可能想了解它在幕后都为您执行什么功能。

毫不夸张地说,没有事务就不能编写可靠的分布式应用程序。事务允许采用 某种控制方式修改应用程序的持久性状态,以便使应用程序对于各种各样的系统 故障(包括系统崩溃、网络故障、电源故障甚至自然灾害)更加健壮。事务是构 建容错、高可靠性以及高可用性应用程序所需的基本构建块之一。

事务的动机

假设您正在从一个账户向另一个账户进行转账个账户差额由数据库表中的某 一行来表示。如果您想从账户 A 转账到账户 B,则可能执行如下这些 SQL 代码 :

SELECT accountBalance INTO aBalance
FROM Accounts WHERE accountId=aId;
IF (aBalance >= transferAmount) THEN
UPDATE Accounts
SET accountBalance = accountBalance - transferAmount
WHERE accountId = aId;
UPDATE Accounts
SET accountBalance = accountBalance + transferAmount
WHERE accountId = bId;
INSERT INTO AccountJournal (accountId, amount)
VALUES (aId, -transferAmount);
INSERT INTO AccountJournal (accountId, amount)
VALUES (bId, transferAmount);
else
FAIL "Insufficient funds in account";
END if

到目前为止,这段代码看起来非常简单易懂。如果手头的资金充足,则从一 个账户中减去资金,并添加到另一个账户中。但是,如果出现系统电源故障或者 崩溃,又会发生什么情况呢?表示账户 A 和账户 B 的行可能不会存储在同一个 磁盘块中,这意味着要完成转账需要进行多个磁盘 IO。如果在已写入第一个磁 盘块之后,在写入第二个磁盘块之前,系统发生故障,又会发生什么情况呢?A 账户中的资金已经划走,但是没有出现在账户 B 中(A 和 B 客户都不会愿意) ,或者资金将出现在账户 B 中,但是没有记入账户 A 的借出账中(银行不会愿 意)。如果账户已正确更新,而账户日记账没有更新,又会发生什么情况呢?那 么账户 A 和账户 B 的每月银行结账单将与它们账户的余额不一致。

不仅不可能同时将多个数据块写入磁盘,而且每当进行修改时马上将每个数 据块写入磁盘,也对系统性能有不利影响。将磁盘写入延迟到比较适宜的时间可 能会大大改善应用程序的吞吐量,但是,需要采用不损害数据完整性的方式执行 。

甚至在系统没有发生故障时,上面讨论的代码还有另一种风险 —— 并发性 。如果账户 A 中有 100 美元,但是却同时开始向它的两个不同的账户分别转账 100 美元,那么会发生什么情况呢?如果时间上凑巧,并且没有适当的锁定机制 ,两次转账都可能成功,从而使账户 A 的余额为负值。

这些情况似乎都是非常可能发生的,因此希望企业数据系统能够解决这些问 题是理所应当的。我们希望在发生火灾、洪水、电源故障、磁盘以及系统出现故 障时,银行都能够保持正确的账户记录。可以通过冗余(冗余的磁盘、计算机以 及数据中心)来提供容错,但是事务 使得构建容错的软件应用程序成为可能。 事务提供了一个框架,用于在系统或组件发生故障时保持数据一致性和完整性。