什么是事务?
考虑一下下面的场景:一个用户想要购买一份在线报纸的使用权并要求通过网上银行提供的帐户来支付。一旦报纸的站点接到用户的银行支票,他们会发送一个电子证书给用户授权访问他们的站点。理想情况下用户希望帐户的记账,证书的交付会都发生或者都不发生。遗憾的是,软件和硬件的失败都可能影响其中一个事件的正常发生,从而使系统在一个不确定的状态。
原子事务(事务)要求要么发生要么都不发生(all-or-noting),它保证程序在发生故障时的稳定性。事务拥有下面的ACID属性:
l 原子性(Atomicity):事务要么成功执行(提交),要么所有的动作都不发生(回滚)。
l 一致性(Consistency):事务产生一致的结果并且保证程序的完整性约束。
l 隔离性(Isolation):事务执行时的中间状态对其它事务是不可见的。此外事务应该表现为连续执行,即使实际是并发执行的。
l 持久性(Durability):提交事务的结果是永久性的(即使是灾难性的故障)
一个事务只能以两种方式结束:提交或者回滚。当事务提交时,它所引起的所有改变都要被持久化(强制到稳定的介质上,例如硬盘)。如果事务失败,所有的操作都要回滚。原子性动作可以被嵌套;嵌套的结果是在外层(顶层)事务内部做临时的提交或回滚。
提交协议
两阶段提交协议用来保证所有参与的动作要么提交要么都回滚。图1说明了提交协议的大致情况。在第一阶段,动作调度者C,尝试与左右的动作参与者A和B通讯,来确定他们将提交还是失败。一个参与者的失败将扮演否决者的角色,导致整个动作的失败。基于他们的响应,调度者会做出提交还是回滚的决定。如果提交动作,调度者会纪录这个决定到稳定的存储介质上,协议进入第2阶段,调度者促使参与者执行决定。如果动作失败,调度者同样会通知参与者。
当一个参与者收到来自调度者的第一阶段信息时,他会纪录足够的信息到存储介质上来提交或者回滚动作引起的修改。返回阶段一的响应后,每个参与者都会保持锁定状态知道它受到调度者阶段二的消息。在收到消息之前,这些资源对其它动作来说是不可用的。如果调度者在传递这个消息之前发生异常,这些资源会继续锁定。不过,如果出问题的部分最终复原,那么损毁修复机制会出去这个协议并中止动作。
图 1 两阶段提交协议
事务代理
动作调度者拥有一个事务上下文(transaction context),参与动作的资源都要求注册在里面。这些资源需要遵守事务提交协议来保证ACID特性;也就是说资源需要提供特殊的方法供动作在协议提交或回滚期间来调用。不过,用这种方式不一定能保证所有的资源都满足事务性,例如,继承了不能修改的代码。为了在动作中使用这些资源常常通过使用事务代理:代理由动作注册并作为一个事务性资源来使用,它实现了特定的工作来使得资源表现出事务性。这就要求代理参与到提交/回滚协议中来。由于代理表现为动作的一部分,所以要保证要么提交要么回滚,无论失败是动作调度者抑或动作参与者造成的。
事务嵌套
假定一个系统为特定的操作提供事务,有时候可能需要将这些操作组合成一个另外的操作,而这个组合的操作也要求成为一个事务。这个组合事务的结果是由一系列组成它的事务的结果组成的。组成这个结果事务的事务被称为嵌套(或子事务)事务,这个组合事务被称为封装事务。封装事务有时候被当作嵌套事务的父母提起。一个分级事务结构可以由这种情况导致:层次的根节点被称为顶层事务。
嵌套事务和顶层事务最大的不同是:嵌套事务的影响只是在其封装事务之外临时性的提交/回滚,例如,如果封装事务失败,即使嵌套事务被提交了,它的结果也会被恢复。
子事务是一个很有效的机制,原因基于以下两点:
l 失败隔离(fault-isolation):子事务的回滚不会导致封装事务的回滚,进而取消整个完成的工作部分。
l 模块性(modularity):如果已经有一个事务与调用相关联的同时,有一个新的事务要开始,那么这个事务会嵌套在它里面。因此,了解对象需要的事务的程序员可以在对象内部来使用它们;如果对象的方法不通过客户事务来调用,这个对象的事务就是顶层事务;否则,他们会被起岸套在客户事务范围内。同样的,一个客户端可以不需要知道对象是事务性的,并开始它自己事务。
对象事务服务
CORBA(Common Object Request Broker Architecture,公共对象请求代理体系结构,通用对象请求代理体系结构),由OMG定义,是该组织为解决基于分布式对象概念的程序共享而提出的一套标准。这个框架主要包括以下组件:
l 对象请求代理(ORB)。可以是对象在分布式、异构环境中显式的发送和接收请求。这个组件是OMG关系模型的核心。
l 对象服务,一系列服务为适应和实现对象提供功能。这些服务被认为是构建分布式程序的需要所在。与本指南相对应的是对象事务服务(OTS)。
l 公共设施(Common Facilities):程序可能用到的另一个很有用的服务,但不是必需的,如桌面管理和帮助工具。
CORBA体系被构造成允许它的实现在里面,综合了多种对象的系统。详细地说,程序与对象的位置以及实现它的语言无关,除非对象提供的接口明确地指出这种需求。在OMG的CORBA服务文档里,对象服务被定义为一个服务(接口和对象)的集合,它们为使用和实现对象提供基础性的功能,这些服务在构建分布式应用程序中是必需的,并且不依赖于程序的域。文档指定了一些核心服务包括命名、时间管理、持久化、同步控制和事务。
OTS规范允许嵌套事务。不过,它的实现不需要提钩这个功能。在这种情况下如果尝试使用嵌套事务会有相应的异常抛出。JBOSSTS完全符合OTS1.1版的规范,并且支持嵌套事务。
事务服务提供接口允许多线程,分布式对象在同一事务中协作,从而可以使所有的对象一起提交或者回滚操作。虽然如此,OTS没有要求所有的对象都拥有事务能力。对象可以选择一点都不支持事务操作,或者出于某些请求来支持它。事务信息可以在客户端和服务端之间显式或隐式的传播,在事务处理期间提供给程序员来做出良好的控制。对象支持(局部的)事务能力需要实现接口TransactionalObject 。
事务服务规范同样区分了可恢复对象和事务性对象。可恢复性对象是那些拥有实际状态(可能会由事务发生变化)对象,因此需要在事务提交或回滚时通知这些对象来确定状态的改变的一致性。这个过程通过向事务注册适当的对象来完成,这些对象实现了Resource接口(或者SubtransactionAwareResource接口)。可恢复性对象同样需要定义事务对象。
相反,一个简单的事务性对象不必是一个可恢复性对象,前提是它的竹田已经有其他的可恢复性对象实现了。一个简单事务对象不需要参与提交协议来决定事务的结果,因为它自身没有任何状态,协议由其委派的其它可恢复性对象来参与。
OTS是一个简单的协议引擎来保证事务行为的遵守而不是通过直接支持上述事务属性。同样它需要其它实现所需功能的协作服务,包括:
l 持久化/恢复服务,支持原子性和持久性。
l 并发控制服务,只是隔离性。
程序开发者需要使用恰当的服务来确保事务对象保持必需的ACID属性。
y