![](https://csdnimg.cn/release/download_crawler_static/86352819/bg3.jpg)
典型事务有几个参与者 —— 应用程序、事务监视器(TPM)以及一个或多个资源管理器(RM)。资源管
理器存储应用程序状态,常常是数据库,但也可能是消息队列服务器(在 J2EE 应用程序中,它们将是 JMS
提供者)或其他事务性资源。TPM 协调 RM 的活动,以确保事务 “要么全有要么全无” 属性。
当应用程序请求容器或事务监视器启动新的事务时,事务开始。由于应用程序访问各种各样的 RM,因此,
在事务中对它们进行
征用
。RM 必须使对应用程序状态所做的任何更改与请求更改的事务相关联。
当发生以下事件之一或者两个事件都发生时,事务结束:事务应用程序
提交
该事务;通过应用程序或者由
于其中一个 RM 失败,
回滚
该事务。如果事务成功提交,则将写入与该事务相关联的更改,以使更改持
久化并使其对于新的事务可见。如果事务被回滚,则该事务所做的所有更改都将被丢弃;就好像该事务从
来没有发生过一样。
事务日志 —— 持久性的关键
事务 RM 通过在一个事务日志中记录多个事务的结果,获得持久性以及可接受的性能。事务日志存储为连
续的磁盘文件(有时存储在原始分区中),并且一般只是用于写入而不用于读取,回滚或恢复的情况例外。
在我们的银行账户示例中,与账户 A 和账户 B 相关联的余额将在内存中进行更新,新的余额和旧的余额
将被写入到事务日志中。编写事务日志的更新记录不需要将全部数据都写入磁盘(只需要写入已更改的数
据,而不需要写入全部磁盘块),而且所需的磁盘寻道时间也会更少(原因是所有更改都包含在日志中连
续的磁盘块中)。此外,与多个并发事务关联的更改可以合并到一起,一次写入事务日志,这意味着每次
磁盘写入时我们可以处理多个事务,而不需要 每个事务进行几次磁盘写入。之后,RM 将根据所更改的数
据更新实际的磁盘块。
重新启动时进行恢复
如果系统出现故障,重新启动时要做的第一件事就是重新应用所有已提交事务的作用,所有这些已提交的
事务都 位于日志中,但是它们的数据块尚未更新。采用这种方式,日志保证了故障之间的持久性,而且还
能够减少所执行的磁盘 IO 操作的数量,或者至少使它们延迟到对系统性能影响更小的时间。
两阶段提交
很多事务只涉及一个 RM —— 通常是数据库。在这种情况下,RM 通常执行提交或回滚事务所需的大部
分工作。(几乎所有事务 RM 都有它们自己的内置的事务管理器,这个管理器可以处理
本地事务
—— 只
涉及该 RM 的事务)。但是,如果事务涉及两个 RM 或多个 RM —— 可能是两个单独的数据库,或者是
一个数据库和一个 JMS 队列,或者是两个单独的 JMS 提供者 —— 我们想确保 “要么全有要么全无” 的
语义不仅仅应用于这个 RM 中,而且还应用于事务中的所有 RM。在这种情况下,TPM 将组织一个
两阶
段提交
。在两阶段提交中,TPM 首先向每个 RM 发送一个 “准备” 消息,询问它是否准备就绪以及是否能
够提交事务;如果它收到来自所有 RM 的确认应答,则将事务在其自己的事务日志中标记为已提交,然后
指示所有 RM 提交事务。如果某个 RM 失败,则重新启动时它将向 TPM 询问有关失败时未处理的所有
事务的状态,并提交它们或者对它们执行回滚操作。
两个阶段提交类似于社会上的结婚典礼 —— 牧师或神父询问双方 “您愿意让这个男人/女人作为您的丈夫/
妻子吗?” 如果双方都回答是,则将宣布他们成为夫妻;否则,双方不能结婚。不管双方中的哪一方首先
说 “我愿意”,在一方没有回答时,另一方决不能完成结婚。
回页首
事务作为处理异常的机制
您可能观察到,事务向对块进行同步的应用程序数据提供很多与内存中数据相同的功能 —— 保证原子性、
更改的可见性以及显而易见的排序。但是,当同步主要是并发控制的机制时,则事务主要是处理异常的机
制。如果在一个磁盘不会发生故障、系统和软件不会崩溃以及电源是百分百可靠的世界中,我们将不需要
事务。事务在企业应用程序中所起的作用与合同法在社会上所起的作用一样 —— 它们规定,如果一方不
能履行他那一部分合同,则交易将失效。当我们编写合同时,我们通常希望它是多余的,令人感到欣慰的
是大部分时候都是如此。