JTA 分布式事务参考
平均分 (38个评分)
为本文评分
开发人员使用开发人员接口,实现应用程序对全局事务的支持;各提供商(数据库,JMS 等)依据提供商接口的规范提供事务资源管理功能;事务管理器( TransactionManager )将应用对分布式事务的使用映射到实际的事务资源并在事务资源间进行协调与控制。 下面,本文将对包括 UserTransaction、Transaction 和 TransactionManager 在内的三个主要接口以及其定义的方法进行介绍。
面向开发人员的接口为 UserTransaction (使用方法如上例所示),开发人员通常只使用此接口实现 JTA 事务管理,其定义了如下的方法:
begin()- 开始一个分布式事务,(在后台 TransactionManager 会创建一个 Transaction 事务对象并把此对象通过 ThreadLocale 关联到当前线程上 )commit()- 提交事务(在后台 TransactionManager 会从当前线程下取出事务对象并把此对象所代表的事务提交)rollback()- 回滚事务(在后台 TransactionManager 会从当前线程下取出事务对象并把此对象所代表的事务回滚)getStatus()- 返回关联到当前线程的分布式事务的状态 (Status 对象里边定义了所有的事务状态,感兴趣的读者可以参考 API 文档 )setRollbackOnly()- 标识关联到当前线程的分布式事务将被回滚面向提供商的实现接口主要涉及到 TransactionManager 和 Transaction 两个对象
Transaction 代表了一个物理意义上的事务,在开发人员调用 UserTransaction.begin() 方法时 TransactionManager 会创建一个 Transaction 事务对象(标志着事务的开始)并把此对象通过 ThreadLocale 关联到当前线程。UserTransaction 接口中的 commit()、rollback(),getStatus() 等方法都将最终委托给 Transaction 类的对应方法执行。Transaction 接口定义了如下的方法:
commit()- 协调不同的事务资源共同完成事务的提交rollback()- 协调不同的事务资源共同完成事务的回滚setRollbackOnly()- 标识关联到当前线程的分布式事务将被回滚getStatus()- 返回关联到当前线程的分布式事务的状态enListResource(XAResource xaRes, int flag)- 将事务资源加入到当前的事务中(在上述示例中,在对数据库 A 操作时 其所代表的事务资源将被关联到当前事务中,同样,在对数据库 B 操作时其所代表的事务资源也将被关联到当前事务中)delistResourc(XAResource xaRes, int flag)- 将事务资源从当前事务中删除registerSynchronization(Synchronization sync)- 回调接口,Hibernate 等 ORM 工具都有自己的事务控制机制来保证事务, 但同时它们还需要一种回调机制以便在事务完成时得到通知从而触发一些处理工作,如清除缓存等。这就涉及到了 Transaction 的回调接口 registerSynchronization。工具可以通过此接口将回调程序注入到事务中,当事务成功提交后,回调程序将被激活。TransactionManager 本身并不承担实际的事务处理功能,它更多的是充当用户接口和实现接口之间的桥梁。下面列出了 TransactionManager 中定义的方法,可以看到此接口中的大部分事务方法与 UserTransaction 和 Transaction 相同。 在开发人员调用 UserTransaction.begin() 方法时 TransactionManager 会创建一个 Transaction 事务对象(标志着事务的开始)并把此对象通过 ThreadLocale 关联到当前线程上;同样 UserTransaction.commit() 会调用 TransactionManager.commit(), 方法将从当前线程下取出事务对象 Transaction 并把此对象所代表的事务提交, 即调用 Transaction.commit()
begin()- 开始事务commit()- 提交事务rollback()- 回滚事务getStatus()- 返回当前事务状态setRollbackOnly()getTransaction()- 返回关联到当前线程的事务setTransactionTimeout(int seconds)- 设置事务超时时间resume(Transaction tobj)- 继续当前线程关联的事务suspend()- 挂起当前线程关联的事务在系统开发过程中会遇到需要将事务资源暂时排除的操作,此时就需要调用 suspend() 方法将当前的事务挂起:在此方法后面所做的任何操作将不会被包括在事务中,在非事务性操作完成后调用 resume()以继续事务(注: 要进行此操作需要获得 TransactionManager 对象, 其获得方式在不同的 J2EE 应用服务器上是不一样的)
下面将通过具体的代码向读者介绍 JTA 实现原理。下图列出了示例实现中涉及到的 Java 类,其中 UserTransactionImpl 实现了 UserTransaction 接口,TransactionManagerImpl 实现了 TransactionManager 接口,TransactionImpl 实现了 Transaction 接口
图 2. JTA 实现类图
清单 3. 开始事务 - UserTransactionImpl implenments UserTransaction
应用程序从支持分布式事务的数据源获得的数据库连接是 XAConnection 接口的实现,而由此数据库连接创建的会话(Statement)也为了支持分布式事务而增加了功能,如下代码所示:
清单 8. JTA 事务资源处理
public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, IllegalStateException, SystemException { // 得到当前事务中的所有事务资源 List<XAResource> list = getAllEnlistedResouces(); // 通知所有的事务资源管理器,准备提交事务 // 对于生产级别的实现,此处需要进行额外处理以处理某些资源准备过程中出现的异常 for(XAResource xa : list){ xa.prepare(); } // 所有事务性资源,提交事务 for(XAResource xa : list){ xa.commit(); } }
?
回页首
结束语
通过如上介绍相信读者对 JTA 的原理已经有所了解,本文中的示例代码都是理想情况下的假设实现。一款完善成熟的 JTA 事务实现需要考虑与处理的细节非常多,如性能(提交事务的时候使用多线程方式并发提交事务)、容错(网络,系统异常)等, 其成熟也需要经过较长时间的积累。感兴趣的读者可以阅读一些开源 JTA 实现以进一步深入学习。
?
参考资料
学习
Java 官方网站“Java Transaction API Specification”提供了详细的 JTA 信息、包括版本, 规范等,感兴趣的读者可以参考讨论
参与论坛讨论。作者简介
肖国一是一位在 IBM 中国软件开发中心(CSDL)工作的软件工程师,目前从事企业电子商务应用的开发。
王晓利,一位工作在 IBM CSDL 的软件工程师,具有 5 年的 J2EE 开发经验和 2 年的 DB2 存储过程开发经验,目前从事企业电子商务应用的开发。