码迷,mamicode.com
首页 > 其他好文 > 详细

XA事务处理

时间:2015-06-23 12:06:43      阅读:921      评论:0      收藏:0      [点我收藏+]

标签:

为了说明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:

这里体现了一个重要的观点,即虽然您的应用可能使用到多个资源,但仅当这些资源必须在同一个事务范畴内被协调时,才有必要用到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事务环境中,通信仅仅是单向的,两阶段提交没法做到,这是因为事务管理器没法接收到来自资源管理器的响应。大多数事务管理器为了优化性能,尽快释放资源的目的,用多线程处理第一阶段轮询以及第二阶段提交流程。下图展示了两阶段提交的基本流程:

技术分享

XA事务处理

标签:

原文地址:http://my.oschina.net/dyzhou/blog/469597

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!