一、什么是JTA
JTA(Java Transaction API即Java事务API)和它的同胞JTS(Java Transaction Service即Java事务服务),为J2EE平台提供了分布式事务服务。一个分布式事务(distributed transaction)包括一个事务管理器(transaction manager)和一个或多个资源管理器(resource manager)。我们可以将资源管理器看做任意类型的持久化数据存储;事务管理器承担着所有事务参与单元的协调与控制。JTA 事务有效的屏蔽了底层事务资源,使应用可以以透明的方式参入到事务处理中;但是与本地事务相比,XA 协议的系统开销大,在系统开发过程中应慎重考虑是否确实需要分布式事务。若确实需要分布式事务以协调多个事务资源,则应实现和配置所支持 XA 协议的事务资源,如 JMS、JDBC 数据库连接池等。下图为JTA体系架构:
二、主要接口及其方法
开发人员使用开发人员接口,实现应用程序对全局事务的支持;各提供商(数据库,JMS 等)依据提供商接口的规范提供事务资源管理功能;事务管理器( TransactionManager )将应用对分布式事务的使用映射到实际的事务资源并在事务资源间进行协调与控制。
1.面向开发人员的接口:UserTransaction,开发人员通常只使用此接口实现JTA事务管理,其定义了如下的方法:
begin() 开始一个分布式事务,(在后台TransactionManager会创建一个Transaction事务对象并把此对象通过ThreadLocale关联到当前线程上)
commit() 提交事务(在后台TransactionManager会从当前线程下取出事务对象并把此对象所代表的事务提交)
rollback() 回滚事务(在后台TransactionManager会从当前线程下取出事务对象并把此对象所代表的事务回滚)
getStatus() 返回关联到当前线程的分布式事务的状态(Status对象里边定义了所有的事务状态)
setRollbackOnly() 标识关联到当前线程的分布式事务将被回滚
2.面向提供商的实现接口:TransactionManager,本身并不承担实际的事务处理功能,它更多的是充当用户接口和实现接口之间的桥梁。下面列出了 TransactionManager 中定义的方法,可以看到此接口中的大部分事务方法与 UserTransaction 和 Transaction 相同。 在开发人员调用 UserTransaction.begin() 方法时 TransactionManager 会创建一个 Transaction 事务对象(标志着事务的开始)并把此对象通过 ThreadLocale 关联到当前线程上;同样 UserTransaction.commit() 会调用 TransactionManager.commit(), 方法将从当前线程下取出事务对象 Transaction 并把此对象所代表的事务提交, 即调用 Transaction.commit()。TransactionManager 接口定义了如下的方法:
begin() 开始事务
commit() 提交事务
rollback() 回滚事务
getStatus() 返回当前事务状态
setRollbackOnly()
getTransaction() 返回关联到当前线程的事务
setTransactionTimeout(int seconds) 设置事务超时时间
resume(Transaction tobj) 继续当前线程关联的事务
suspend() 挂起当前线程关联的事务
3.面向提供商的实现接口: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。工具可以通过此接口将回调程序注入到事务中,当事务成功提交后,回调程序将被激活。
三、示例
public void transferAccount(){
UserTransaction userTx = null;
Connection connA = null;
Statement stmtA = null;
Connection connB = null;
Statement stmtB = null;
try{
//获得Transaction管理对象
userTx = (UserTransaction)getContext().lookup("\java:comp/UserTransaction");
//从数据库A中取得数据库连接
connA = getDataSourceA().getConnection();
//从数据库 B 中取得数据库连接
connB = getDataSourceB().getConnection();
//启动事务
userTx.begin();
//将A账户中的金额减少500
stmtA = connA.createStatement();
stmtA.execute("update t_account set amount = amount - 500 where account_id = 'A'");
// 将 B 账户中的金额增加 500
stmtB = connB.createStatement();
stmtB.execute("\update t_account set amount = amount + 500 where account_id = 'B'");
// 提交事务
userTx.commit();
// 事务提交:转账的两步操作同时成功(数据库 A 和数据库 B 中的数据被同时更新)
}catch(SQLException sqle){
try{
//发生异常,回滚在本事务中的操纵
userTx.rollback();
//事务回滚:转账的两步操作完全撤销
//(数据库A和数据库B中的数据更新被同时撤销)
stmt.close();
conn.close(); ...
}catch(Exception ignore){
}
sqle.printStackTrace();
}catch(Exception ne){
e.printStackTrace();
}
}
参考:http://www.ibm.com/developerworks/cn/java/j-lo-jta/