最常见的两种事务模型:平面(Flat)事务和嵌入式(Nested)事务。 平面事务是由一系列的原子性的操作构成,这些操作一起组成了单个工作单元。而嵌入式事务容许将原子性的工作单元嵌入到其它的工作单元中,并且对于嵌入式事 务来说,嵌入的子事务即使回滚了,也不会引起外层事务的回滚。但是,如果嵌入式事务最终不能够提交的话,整个事务也将失败。可以将嵌入式事务理解成事务 树,它们存在单个根或顶级(top-level)事务,根事务是主事务。
其它事务模型还有Chained事务、Sagas事务。
当前的EJB规范没有对嵌入式事务做出具体的要求,因此EJB的事务管理器只支持平面事务。
DTP:分布式事务处理( Distributed Transaction Processing , DTP )的概念。 Transaction ,即事务,又称之为交易,指一个程序或程序段,在一个或多个资源如数据库或文件上为完成某些功能的执行过程的集合。分布式事务处理是指一个事务可能涉及多个数据库操作,分布式事务处理的关键是必须有一种方法可以知道事务在任何地方所做的所有动作,提交或回滚事务的决定必须产生统一的结果(全部提交或全部回滚)。
X/Open DTP模型(1994):包括应用程序(AP)、事务管理器(TM)、资源管理器(RM)、通信资源管理器(CRM)四部分。在这个模型中,通常事务管理器(TM)是交易中间件,资源管理器(RM)是数据库,通信资源管理器(CRM)是消息中间件。
XA:是由X/Open组织提出的分布式事务的规范。XA规范主要定义了(全局)事务管理器(Transaction Manager)和(局部)资源管理器(Resource Manager)之间的接口。XA接口是双向的系统接口,在事务管理器(Transaction Manager)以及一个或多个资源管理器(Resource Manager)之间形成通信桥梁。XA之所以需要引入事务管理器是因为,在分布式系统中,两台机器理论上无 法达到一致的状态,需要引入一个单点进行协调。事务管理器控制着全局事务,管理事务生命周期,并协调资源。资源管理器负责控制和管理实际资源(如数据库或 JMS队列)。下图说明了事务管理器、资源管理器,与应用程序之间的关系:
1)事务管理器。事务管理器负责协调具体的资源管理器来完成事务控制。
2)资源管理器。资源管理器具体来说就是各种驱动程序,对于数据库来说,就是具体的JDBC驱动程序。
2PC:是指两阶段提交协议(Two-Phase Commit protocol)
所有关于分布式事务的介绍中都必然会讲到两阶段提交,因为它是实现XA分布式事务的关键(确切地说:两阶段提交主要保证了分布式事务的原子性:即所有结点要么全做要么全不做)。所谓的两个阶段是指:第一阶段:准备阶段和第二阶段:提交阶段。
如上图所示,分布式事务管理的角色一般都是有Transaction Manager (简称TM)来承担。其负责与Application Program(简称AP)、Resource Manager (简称RM) 以及其他的TM进行交互。这里RM所管理的Resource在分布式事务中涉及数据库、队列、文件、消息或其他在事务中被访问到的共享对象。TM一般负责处理基本的事务操作:Start、Commit和Abort。AP调用Start来启动事务的执行,调用 Commit来请求TM提交事务,调用Abort来请求TM中断事务操作。TM在分布式事务执行过程中会跟踪所有事务访问的RM。一旦事务准备提交,TM 就需要和事务涉及到的所有TM打交道来执行2PC.
在上面的两阶段提交中,存在着一个主事务管理器,称之为分布式协调者(distributed Transaction Coordinator,DTC)。运行中的DTC能够协调网络中的其他事务管理器,并控制事务的具体执行。下面是分布式2PC事务的据具体实现过程:
A)事务协调者发生准备提交(prepare to commit)消息给参与事务的各个事务管理器;
B)各个事务管理器可能会将接收到的消息传播给绑定到各个事务管理器的资源管理器;
C)各个事务管理器将运行结果报告给事务协调者。如果所有的事务管理器都希望执行提交操作,则需要将提交操作记录到日志中,以防止系统瘫痪的发生。
D)最后,事务协调者告知各个事务管理器去提交事务。事务管理器收到提交命令后,会依次调用各自资源管理器,从而完成资源的实际更新,并生效它。如果期间出现任何异常,借助日志能够执行恢复操作,从而实现事务的预期目标。
将提交分成两阶段进行的目的很明确,就是尽可能晚地提交事务,让事务在提交前尽可能地完成所有能完成的工作,这样,最后的提交阶段将是一个耗时极短的微小操作,这种操作在一个分布式系统中失败的概率是非常小的,也就是所谓的“网络通讯危险期”非常的短暂,这是两阶段提交确保分布式事务原子性的关键所在。 (唯一理论上两阶段提交出现问题的情况是当协调者发出提交指令后当机并出现磁盘故障等永久性错误,导致事务不可追踪和恢复)
从两阶段提交 的工作方式来看,很显然,在提交事务的过程中需要在多个节点之间进行协调,而各节点对锁资源的释放必须等到事务最终提交时,这样,比起一阶段提交,两阶段 提交在执行同样的事务时会消耗更多时间。事务执行时间的延长意味着锁资源发生冲突的概率增加,当事务的并发量达到一定数量的时候,就会出现大量事务积压甚至出现死锁,系统性能就会严重下滑。这就是使用XA事务。
如果计划用 JTA 界定事务,那么就需要有一个实现 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驱动程序。一个实现了这些接口的驱动程序将可以参与 JTA 事务。一个 XADataSource 对象就是一个 XAConnection 对象的工厂。 XAConnection是参与 JTA 事务的 JDBC 连接。
XA连接区别于非XA连接。要记住的是XA连接是一个JTA事务中的参与者。这就意味着XA连接不支持JDBC的自动提交特性。 也就是说应用程序不必在XA连接上调用java.sql.Connection.commit()或 java.sql.Connection.rollback()。 相反,应用程序应该使用UserTransaction.begin()、UserTransaction.commit()和 UserTransaction.rollback()。
如下式weblogic中的源码片段。
JTSXAResourceImpl源码片段:
public int prepare(Xid xid)throws XAException { if(!jtsConn.getEnable2PC()) throw new XAException("JDBC driver does not support XA ... ); else return 0; } public void commit(Xid xid, boolean flag)throws XAException { ... jtsConn.internalCommit(); ... } public void rollback(Xid xid)throws XAException { ... jtsConn.internalRollback(); ... }
JTSConnection源码片段:
public synchronized void internalRollback() throws SQLException { ... connection.rollback(); ... internalClose(); ... } public void internalCommit() throws SQLException { ... connection.commit(); ... internalClose(); ... }