`

XA事务处理

 
阅读更多

XA协议由Tuxedo首先提出的,并交给X/Open组织,作为资源管理器(数据库)与事务管理器的接口标准。目前,OracleInformixDB2Sybase等各大数据库厂家都提供对XA的支持。XA协议采用两阶段提交方式来管理分布式事务。XA接口提供资源管理器与事务管理器之间进行通信的标准接口。XA协议包括两套函数,以xa_开头的及以ax_开头的。

 

简介

编辑
取决于上下文, XA 有多种意思. 我们常见的数据库连接交易中的 XA 是指由 X/Open 组织提出的分布式交易处理的规范. XA 规范主要定义了事务管理器(Transaction Manager)和局部资源管理器(Local Resource Manager)之间的接口.有人说 XA 是 eXtended Architecture 的缩写, 其实我觉得这仅仅是一种巧合. eXtended Architecture 是一种CD ROM的驱动架构.

XA操作

编辑
以下的函数使事务管理器可以对资源管理器进行的操作:
1)xa_open,xa_close:建立和关闭与资源管理器的连接。
2)xa_start,xa_end:开始和结束一个本地事务
3)xa_prepare,xa_commit,xa_rollback:预提交、提交和回滚一个本地事务。
4)xa_recover:回滚一个已进行预提交的事务。
5)ax_开头的函数使资源管理器可以动态地在事务管理器中进行注册,并可以对XID(TRANSACTION IDS)进行操作。
6)ax_reg,ax_unreg;允许一个资源管理器在一个TMS(TRANSACTION MANAGER SERVER)中动态注册或撤消注册。

本文选自迷你书《Java事务设计策略》的第五章,译者翟静。

为了说明X/Open XA接口在JTA事务管理中的重要性,以及它使用的时机,我们以前一章提到的一段固定收入交易的EJB代码为例:

@TransactionAttribute(TransactionAttributeType.REQUIRED) 

 public void placeFixedIncomeTrade(TradeData trade) throws Exception { 
     try { 
         ... 
         Placement placement =  placementService.placeTrade(trade);
         executionService.executeTrade(placement); 
     } catch (TradeExecutionException e) { 
         log.fatal(e); 
         sessionCtx.setRollbackOnly(); 
         throw e; 
     } 
 }         
 

这段代码中,首先预置了一笔交易,而后执行交易,这两个操作更改了数据库中不同的表。正如我们在前面章节看到的,如果在标准的非XA环境,这段代码保证遵循ACID准则。假设我们收到了一个新的需求,该公司要求在每一笔固定收入交易时都向其他系统发送一条JMS消息,以关注交易活动。为简单起见,我们同样假设在sendPlacementMessage()方法中实现所有的JMS消息逻辑。上面的例子被修改如下以实现新功能:

@TransactionAttribute(TransactionAttributeType.REQUIRED)

public void placeFixedIncomeTrade(TradeData trade) throws Exception { 
    try { 
        ... 
        Placement placement =  placementService.placeTrade(trade); 
        placementService.sendPlacementMessage(placement); 
        executionService.executeTrade(placement); 
    } catch (TradeExecutionException e) { 
        log.fatal(e); 
        sessionCtx.setRollbackOnly(); 
        throw e;
    } 
} 

虽然以上的修改足够简单,这段代码却不会保证ACID准则。如果executeTrade()方法抛出了TradeExecutionException,数据库更改将会回滚,但交易预置的消息将会被发送到JMS的queue或topic。事实上,交易预置消息很可能在sendPlacementMessage()方法执行完成后就被queue或topic释放(消费)掉了。

因为在非XA环境中,消息队列的插入过程独立于数据库更新操作,ACID准则中的原子性和独立性不能得到保证,从而整体上数据完整性受到损害。我们需要的是,有一种方式能够让消息队列和数据库处于单一事务的控制之下,以至于两个资源能被协调形成单一工作单元。使用X/Open的XA接口,我们便能够做到协调多个资源,保证维持ACID准则。

XA接口详解

X/Open XA接口是双向的系统接口,在事务管理器(Transaction Manager)以及一个或多个资源管理器(Resource Manager)之间形成通信桥梁。事务管理器控制着JTA事务,管理事务生命周期,并协调资源。在JTA中,事务管理器抽象为javax.transaction.TransactionManager接口,并通过底层事务服务(即JTS)实现。资源管理器负责控制和管理实际资源(如数据库或JMS队列)。下图说明了事务管理器、资源管理器,以及典型JTA环境中客户端应用之间的关系:

注意,上图中XA接口形成了事务管理器和资源管理器之间的通信桥梁。因为XA接口的双向特质,XA支持两阶段提交协议,我们将在本章的后续部分讨论。

本章所叙述的内容很难覆盖XA接口的所有细节。如果读者关心XA的细节,请参考X/Open XA接口规范(可在http://www.opengroup.org/onlinepubs/009680699/toc.pdf通过pdf的格式拿到)。

什么时候应该使用XA?

在Java事务管理中,常常令人困惑的一个问题是什么时候应该使用XA,什么时候不应使用XA。由于大多数商业应用服务器执行单阶段提交(one-phase commit)操作,性能下降并非一个值得考虑的问题。然而,非必要性的在您的应用中引入XA数据库驱动,会导致不可预料的后果与错误,特别是在使用本地事务模型(Local Transaction Model)时。因此,一般来说在您不需要XA的时候,应该尽量避免使用它。下面的最佳实践描述了什么时候应当使用XA:

最佳实践

仅在同一个事务上下文中需要协调多种资源(即数据库,以及消息主题或队列)时,才有必要使用X/Open XA接口。

 

这里体现了一个重要的观点,即虽然您的应用可能使用到多个资源,但仅当这些资源必须在同一个事务范畴内被协调时,才有必要用到XA。多个资源的情形包括访问两个或更多的数据库(并不止是多个表,而是彼此分开的多个数据库),或者一个数据库加上一个消息队列,又或者是多个消息队列。您可能有一个应用同时使用到一个数据库和一个消息队列。然而,如果这些资源并不在同一个事务中使用,就没有必要去用XA。本章开始的代码,预置一个固定收入交易,而后向队列发送一条消息,就是需要使用XA以便维护ACID特性的例子。

需要并使用XA最常见的场景是在同一个事务中协调数据库更改和消息队列(或主题)。注意这两种操作有可能在应用完全不同的地方出现(特别是在使用像hibernate这样的ORM框架的时候)。XA事务必须在回滚事件发生时协调两种类型的资源,或让更改与其他事务保持隔离。如果没有XA,送往队列或主题的消息甚至会在事务终止前到达并被读取。而在XA环境下,队列中的消息在事务提交之前不会被释放。此外,如果是协调一个操作型数据库和一个只读数据库(即参考数据库),您就不需要XA。然而,由于XA支持“只读优化”,当把一个只读数据源引入XA事务时,您可能并不会看到任何的性能损失。

当意图在您的企业Java应用中使用XA时,有几个隐含的问题是需要考虑的。这些问题包括两阶段提交(2PC,two-phase commit process),经验异常,以及XA驱动的使用。以下章节分别详述了这些问题。

两阶段提交

两阶段提交协议(The two-phase commit protocol,2PC)是XA用于在全局事务中协调多个资源的机制。两阶段协议遵循OSI(Open System Interconnection,开放系统互联)/DTP标准,虽然它比标准本身早若干年出现。两阶段提交协议包含了两个阶段:第一阶段(也称准备阶段)和第二阶段(也称提交阶段)。一个描述两阶段提交很好的类比是典型的结婚仪式,每个参与者(结婚典礼中的新郎和新娘)都必须服从安排,在正式步入婚姻生活之前说“我愿意”。考虑有的杯具情形,“参与者”之一在做出承诺前的最后一刻反悔。两阶段提交之于此的结果也成立,虽然不具备那么大的破坏性。

当commit()请求从客户端向事务管理器发出,事务管理器开始两阶段提交过程。在第一阶段,所有的资源被轮询到,问它们是否准备好了提交作业。每个参与者可能回答“准备好(READY)”,“只读(READ_ONLY)”,或“未准备好(NOT_READY)”。如果有任意一个参与者在第一阶段响应“未准备好(NOT_READY)”,则整个事务回滚。如果所有参与者都回答“准备好(READY)”,那这些资源就在第二阶段提交。回答“只读(READ_ONLY)”的资源,则在协议的第二阶段处理中被排除掉。

由于XA环境中双向通信的能力,两阶段提交变得可能。在非XA事务环境中,通信仅仅是单向的,两阶段提交没法做到,这是因为事务管理器没法接收到来自资源管理器的响应。大多数事务管理器为了优化性能,尽快释放资源的目的,用多线程处理第一阶段轮询以及第二阶段提交流程。下图展示了两阶段提交的基本流程:

下图展示了当资源管理器之一(DBMS)在第一阶段轮询时发生错误的情况下两阶段提交的过程,

在这个示例中,一个提交请求被运行全局事务(global transaction,一个运行于XA之下的JTA事务)的客户端发送到事务管理器。在第一阶段,第二个资源管理器回给事务管理器一个“未准备好(NOT_READY)”响应。在本例中事务管理器对所有参与者发出回滚请求,因此协调了在全局事务中的所有资源。

一些商业的应用容器提供一种称之为“最后参与者支持(Last Participant Support)”的特性,该特性有个另外的名字叫“最后资源提交优化(Last Resource Commit Optimization)”。“最后参与者支持”允许非XA资源参与进全局事务。在“最后参与者支持”下,当一个XA环境的提交请求到达事务管理器,事务管理器会首先对XA资源发起第一阶段流程。一旦XA参与者产生的结果一致返回,事务管理器随即对非XA参与者发起提交(或回滚)的请求。这个请求的结果决定了两阶段提交流程剩下的工作如何进行。如果对非XA资源的请求成功,事务管理器会发起第二阶段,并对XA参与者发起提交请求。如果对非XA参与者的请求不成功,事务管理器会发起第二阶段,并要求所有XA参与者回滚事务。

“最后参与者支持”机制存在两个问题。第一,它不是在应用容器间可移植的。第二,因为在第一阶段轮询过程和非XA最后参与资源提交之间有较长的时间等待,您会发现在使用这一特性时发生经验异常(Heuristic Exception)的几率增加了(将会在下一节详述)。基于这些原因,“最后参与者支持”特性应该在一般情况下避免使用,除非迫不得已。

大多数商业应用服务器还支持另一个优化,称之为“一阶段提交优化(One-Phase Commit Optimization)”。如果事务只包括一个参与者,第一阶段处理会被忽略,单一的参与者被通知提交。在这种情况下,整个XA事务的后果取决于单一参与者的结果。

经验异常(Heuristic Exception)处理

在两阶段提交的过程,资源管理器可能会使用“经验化决策”的策略,或者提交,或者回滚它自己的工作,而不受事务管理器的控制。“经验化决策”是指根据多种内部和外部因素做出智能决定的过程。当资源管理器这么做了,它会向客户端报上一个经验异常(Heuristic Exception)。

所幸的是,经验异常并不是特别常见。它仅仅发生在XA环境下,做两阶段提交的过程中,特别是事务参与者在第一阶段产生了响应之后。经验异常最常见的原因是第一阶段和第二阶段之间的超时情况。当通讯延迟或丢失,资源管理器或许要做出提交或回滚其工作的决定,以释放资源。不出意料,经验异常发生最频繁的时候正是高资源利用时间段。当您在应用中发现经验异常时,您应该查找是否有事务超时问题,资源锁定问题,以及资源使用过量问题,这些问题常常是经验异常的根本原因。偶尔网络延迟或网络故障也会导致经验异常。同样的,如上面的章节所述,使用“最后参与者支持”特性会导致经验异常更为频繁的发生。

JTA暴露出的三种JTA经验异常为HeuristicRollbackException,HeuristicCommitException,以及HeuristicMixedException。我们分别用下面的场景说明之:

场景1:在commit操作阶段的HeuristicRollbackException异常

在此场景中,客户端在XA环境下执行更新操作,向事务管理器发起提交当前事务的请求。事务管理器开启两阶段提交流程的第一阶段,随即轮询资源管理器。所有资源管理器向事务管理器报告说它们已经做好了提交事务的准备。然而,在(两阶段提交流程的)第一阶段和第二阶段之间每个资源管理器独立的做出了回滚它们已完成工作的经验性决定。当进入第二阶段,提交请求被发送到资源管理器时,因为所做的工作已经在此之前回滚了,事务管理器将会向调用者报告HeuristicRollbackException异常。

当接受到此类异常时,常用的正确处理方式是将此异常传回客户端,让客户端重新提交请求。我们不能简单的再次调用commit请求,因为对数据库产生的更新已经随回滚操作从数据库事务日志中删除了。下面的序列图说明了这一场景:

第一步:第一阶段处理(准备阶段)

第二步:在第一阶段和第二阶段之间

第三步:第二阶段处理(提交阶段)

正如您从序列图中看到的,两个资源管理器回滚了他们自己的工作,虽然他们在第一阶段都向事务管理器报告了READY的响应。别担心这些异常因何发生,我们在后续章节会做深入探讨。

场景2:在commit操作阶段的HeuristicMixedException异常

在此场景中,客户端在XA环境下执行更新操作,向事务管理器发起提交当前事务的请求。事务管理器开启两阶段提交流程的第一阶段,随即轮询资源管理器。所有资源管理器向事务管理器报告说它们已经做好了提交事务的准备。和第一种场景不同的是,在第一阶段和第二阶段发生的间隙,有资源管理器(例如消息队列)做出了经验性的决定提交其工作,而其他资源管理器(例如数据库)做出了回滚的经验性决定。在这种情况下,事务管理器向调用者报告HeuristicMixedException异常。

这种情况下,非常难于选择正确的后续应对方式,因为我们不知道哪些资源提交了工作,哪些资源回滚了工作。所有目标资源因此处于一种不一致的状态。因为资源管理器彼此互不干预的独立操作,就经验性决定而言,他们之间没有任何协调和通信。解决这一异常通常需要人力介入。下面的序列图说明了这一场景:

第一步:第一阶段处理(准备阶段)

第二步:在第一阶段和第二阶段之间

第三步:第二阶段处理(提交阶段)

注意在上面的图示中,一个资源管理器提交了它的工作,而其他资源管理器选择回滚其工作。在这种情况下事务管理器将会报告HeuristicMixedException。

对消息队列或主题使用XA

在XA接口下使用的资源必须实现javax.transaction.xa.XAResource接口,以便自己能够加入XA全局事务。对于JMS目标(队列或主题),这可以通过在特定的应用服务器控制台或管理程序中配置完成。真正激活XA的部分是JMS连接工厂(Connection Factory)。一旦JMS连接工厂支持XA,发送给JMS队列或主题的消息在两阶段提交过程结束之前不会被释放。在没有XA的情况下,不论所处的事务上下文结果如何,发送给JMS目标的消息会被立即释放,并可被接收者拾取。

在WebLogic应用服务器中,可在管理控制台的Services|JMS|Connection Factories配置中激活XA的JMS连接工厂。在Transactions这个页面,有一个名为XA Connection Factory Enabled的选项,经由此可以将JMS目标包含到JTA全局事务中。对于IBM WebSphere,可在管理控制台的Resources|WebSphere JMS Providers|Connection Factories路径下选择使用XA的JMS连接工厂功能。勾上名为EnableXA的选择框就激活了XA的JMS连接工厂。

为数据库使用XA

可通过使用XA版的数据库驱动来使数据库支持XA。由于XA版的数据库驱动通常比非XA的难用许多,一个忠告是不到不得已的时候别使用XA驱动。

使用XA版的数据库驱动常会导致不可预期且难于解决的错误。例如,将非XA驱动替换为XA版驱动常常会产生难于跟踪的错误。因此,应该在项目开发和测试阶段尽早的引入XA驱动(,及早暴露问题并解决之)。

在使用XA版的数据库驱动时,可能碰到的错误种类包括本地事务错误和嵌套事务错误。当您在一个XA全局事务正在进行的过程中试图开启新的事务,这些错误就会产生。这种情形会在多个环境下发生,但最常见的情况是混合本地事务模型与声明式事务模型导致,以及在XA环境下使用存储过程的情况。

当在XA环境下使用存储过程,在存储过程里调用DDL(数据定义语句,如CREATE TABLE,BEGIN TRAN,END TRAN)常导致错误。这是最频繁导致XA错误的罪魁祸首,并很难修正。例如在Oracle中,使用XA时,您可能会看到下面的错误信息:

ORA-02089: COMMIT is not allowed in a subordinate session

如果使用非XA的数据库驱动,大概您不会看到这个错误,因为DDL语句执行的时候JTA事务会暂停。当看到这个错误信息,表明了您的存储过程中包含DDL代码,并且(由资源管理器管理的)本地事务尝试提交它的工作。

通常要从存储过程中删除既有的DDL语句是困难的,因为它们在那里一定有存在的理由,或者也许这些存储过程被其他应用所共享(,要删除它们牵扯面太大)。一个有效的绕开问题的做法是,调用这些存储过程之前,手工的暂停事务;而在这些存储过程返回后,继续事务。使用这个技巧会避免XA相关的本地和嵌套错误。然而,如果这样做,存储过程做出的修改会独立于JTA全局事务提交,因此违背了事务的ACID特性。所以说,这种做法仅仅是绕开问题,而不是解决问题。下面的代码片段展示了此技巧的细节:

... 
InitialContext ctx = new InitialContext(); 
TransactionManager tm = (javax.transaction.TransactionManager) 
ctx.lookup(“javax.transaction.TransactionManager”); 
Transaction currentTx = null; 

try { 
    currentTx = tm.suspend(); 
    invokeSPWithDDL(); 
} finally { 
    if (currentTx != null)
    tm.resume(); 
} 

即便在声明式事务的环境下,我们仍然可以使用TransactionManager去用代码方式暂停和继续事务。这个技巧能够避免XA环境下的SQL异常信息,但它没有真正的解决问题。——真正解决问题的唯一方法是在有关存储过程中删除那些犯规的DDL语句,或者使用支持嵌套事务的JTA事务服务。

总结

本章要表达的最重要的思想是,理解什么时候您真正需要使用XA版的数据库驱动。许多开发人员和架构师总是坚持要使用XA版的数据库驱动,虽然事实上不存在使用它们的合理理由。如果您需要在同一个事务中协调多个更改的资源(数据库、消息队列、主题,或者JCA),那么毫无疑问您需要引入XA接口。否则,千万避开XA。

另一条关于使用XA的建议是,碰到问题时别总去猜测您使用的是一个可能错误百出的XA数据库驱动。问题很有可能是您的应用代码或事务处理逻辑造成的,而非XA驱动。

分享到:
评论

相关推荐

    掌握分布式事务的艺术:深入MySQL XA事务处理

    ### 掌握分布式事务的艺术:深入 MySQL XA 事务处理 #### 1. 分布式事务与 XA 事务概述 ##### 1.1 分布式事务定义 分布式事务是指那些跨越多个数据库实例或者服务的事务。这类事务的管理比单一数据库上的事务更加...

    WebSphere MQ与Oracle 数据库的XA事务(两阶段提交)实现

    总的来说,理解并掌握WebSphere MQ的XA事务处理和两阶段提交机制对于构建高可用、强一致性的分布式系统至关重要。这种技术不仅适用于WMQ与Oracle数据库的组合,还可以应用于其他支持XA的资源管理器,实现更复杂的...

    使用Atomikos处理ActiveMQ在Spring环境的XA事务

    标题“使用Atomikos处理ActiveMQ在Spring环境的XA事务”揭示了本文将涉及的关键技术领域,即在Spring框架中如何利用Atomikos这个开源事务管理器来支持分布式事务,特别是针对ActiveMQ消息队列的XA事务处理。...

    xa分布式事务处理

    分布式事务处理是解决多数据库系统中一致性问题的关键技术,而X/Open Distributed Transaction Processing (DTP)模型和XA规范是这一领域的重要理论基础和实现标准。X/Open组织,现称为Open Group,于1994年提出了DTP...

    MySQL 外部XA及其在分布式事务中的应用分析

    本文将深入讨论与理解分布式事务处理原理,MySQL XA事务的具体分类(包括内部XA与外部XA),以及在分布式环境下实现一致性事务处理所面临的挑战和解决策略。 在MySQL数据库中,XA事务通过两阶段提交协议(2PC)来...

    mysql分布式事务实现 MySQL XA pdf

    ### MySQL分布式事务处理与XA协议详解 #### 一、引言 在当今互联网技术高度发展的背景下,分布式系统已经成为处理大规模数据的关键技术之一。而在分布式环境中,确保数据的一致性成为了非常重要的挑战。其中,...

    JMS MDB 与 XA 事务-002

    在IT行业中,Java消息服务(Java Message Service,简称JMS)和分布式事务处理(Distributed Transaction Processing,简称DTP)的XA事务是企业级应用中关键的组件,尤其是在构建高可用性和可伸缩性的系统时。...

    Oracle SOA 套件和 RAC 数据库事务一致性配置指南

    为了确保 Oracle SOA 套件能够支持 XA 事务处理,在特定版本的 Oracle SOA 套件、Oracle 应用服务器和 JDBC 上需要安装一系列必要的补丁。具体来说,对于 Oracle RAC 数据库 10g 的 XA 部署,Oracle SOA 套件支持 ...

    sysbench-xa:从标准sysbench性能测试工具衍生而来,添加了测试用例和脚本来测试mysql XA事务处理的性能,还添加了python脚本以生成漂亮的报告网页

    关于 SysBench是一个模块化,跨平台和多线程的基准测试工具,用于评估OS参数,这些参数对于在高负载下运行数据库的系统非常重要。 该基准套件的想法是快速获得有关系统性能的印象,而无需设置复杂的数据库基准,...

    分布式事务常用的解决方案,XA,Saga,TCC,MQ补偿.docx

    XA(eXtended Architecture)是开放集团(Open Group)提出的分布式事务处理规范,被广泛应用于数据库厂商。XA规范定义了分布式事务处理的模型和接口,确保了事务的一致性和可靠性。MySQL从5.x版本开始支持XA规范,...

    DTP分布式事务处理规范XA.pdf

    《X/Open分布式事务处理规范XA》是X/Open(现为The Open Group)发布的一个重要的技术标准,主要关注在分布式计算环境中如何协调多个资源管理器进行一致性的事务处理。该规范定义了一个接口,允许应用程序和资源管理...

    Mysql事务控制(XA分布式事务)和锁定语句

    在分布式系统中,MySQL支持通过X/Open XA协议实现的分布式事务,这允许跨越多个资源管理器(如不同的数据库实例)的事务一致性。分布式事务的处理分为两个主要阶段: 1. **预提交阶段(Prepare Phase)**:在这一...

    mysql的XA事务恢复过程详解

    7. **处理准备状态的事务**:一旦所有非XA事务的回滚完成,InnoDB会继续处理那些处于预提交状态的XA事务。这通常涉及到与外部事务协调器通信,以确定这些事务应该被提交还是回滚。 8. ** xa recover 命令**:在...

    Java事物设计策略

    ### XA事务处理 对于涉及多个资源管理器的分布式事务,XA协议是实现两阶段提交的关键。两阶段提交过程分为准备阶段和提交阶段,确保了事务在所有参与者中的一致性。然而,XA事务也存在启发式异常处理的挑战,即在...

    事务处理--介绍事务原理和事务实现.docx

    在IT领域,事务处理是数据库管理系统中的核心概念,它确保了数据的一致性和完整性。本文将深入探讨事务的原理和实现方法。 1. **什么是事务** 事务是一系列数据库操作的逻辑单元,这些操作要么全部成功执行,要么...

    Java事务处理详细介绍

    ### Java事务处理详细介绍 #### 一、什么是Java事务 在软件开发领域,特别是涉及数据库操作的应用中,**事务处理**是非常关键的一个概念。通常人们认为事务处理与数据库操作紧密相关,其实事务的概念远不止于此。...

    Java中的事务处理

    在Java编程领域,事务处理是确保数据一致性与完整性的关键机制。它主要用于数据库操作,确保一组操作要么全部成功,要么全部失败,遵循ACID(原子性、一致性、隔离性和持久性)原则。以下是对Java中事务处理的详细...

Global site tag (gtag.js) - Google Analytics