JTA

一、什么是JTA

JTA全称Java Transaction API ,它是Java中用来规范定义分布式事务处理的标准,其标准编号为JSR 907。

二、如何保证分布式事务

一个业务单元,它所涉及的操作,需要对多个数据库进行修改。这些修改需要一并成功,要么全部回滚,即需要保证跨多个数据库操作的ACID事务性。我们知道单个数据库支持事务,那如何保证分布式数据处理的事务性呢?答案是:X/Open XA**

三、什么是X/Open XA

X/Open XA是一个工业标准,简称XA。他提供了一组本地资源管理器(比如单个数据库)和全局事务管理器(global transaction manager)之间的调用接口。使得全局事务管理器可以通过这些接口协调进行对多个数据库的事务管理来控制分布式事务的ACID特性。

所有实现了XA标准的资源,都可以加入到分布式事务中进行分布式事务处理,比如Oracle,Mysql等,都实现了XA标准。

单个XA标准事务,采用两步提交协议来进行事务提交:

  • Prepare
  • Commit

当Prepare返回ok后,则Commit,否则进行回滚等其它操作。

四、分布式事务实现

从XA标准的定义,可以看到为了保证分布式事务,需要两个角色:

  • XA资源
  • 全局事务管理器

实现XA的资源,表示我可以支持分布式事务管理,快来使用我吧。

全局事务管理器,像一个导演一样,实际来调度编排基于多个XA资源的分布式事务。

于是一个分布式事务的伪代码不外乎如下:

con1 = XAResouce1.getConnection...   
con2 = XAResouce2.getConnection...   

con1 do some thing.   
con2 do some thing.   
after they finish.   

pre1 = XAResouce1.prepare();   
pre2 = XAResouce2.prepare();   

if( both pre1 and pre2 are OK){   
XAResouce1 and 2 commit   
}else {   
XAResouce1 and 2 rollback   
}  

五、详解JTA

JTA便是以上分布式事务处理模型在Java中的映射,他们以接口方式规范定义,除开上述两种角色外,为了降低分布式事务处理代码难度,JTA还引入了第三个角色UserTransaction

所以JTA定义的三个接口如下:

  • javax.transaction.xa.XAResource
  • javax.transaction.TransactionManager
  • javax.transaction.UserTransaction

1、XAResource

在java中,访问具体数据库的适配器是JDBC,所以JDBC driver需要实现XAResource接口,由JDBC来代表XAResource,也即数据库。JDBC 驱动一般由数据库厂商提供。

2、TransactionManager

TransactionManager像一个导演,实际来协调各XAResource事务,让他们组成一个分布式事务处理单元。这具有一定的复杂性。许多web容器实现了该接口,故分布式事务管理可交给Web容器负责,对开发者透明。

3、UserTransaction

该接口供应用开发人员使用,他简化了分布式事务开始和提交的难度,从而让分布式事务处理代码简洁易维护。具体的使用JTA使用代码如下:

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();
    }
}

六、总结

从JTA标准我们可以看出java社区在处理类似事情的思想。往往是以面向对象的思想,高度抽象出一个技术点所涉及的关键步骤和角色,定义出接口。然后具体实现分派给各厂商,这些实现最终像可替换的组件一样插拔,只要遵循接口规范即可。这就是面向接口编程吧。

值得注意的是,为了简化文章说明,故将支持XA标准的XAResource等价说成了数据库,实际上XAResource指代任何支持XA标准的资源,比如JMS等。

七、参考链接

https://en.wikipedia.org/wiki/JavaTransactionAPI
https://en.wikipedia.org/wiki/X/Open_XA
https://www.progress.com/jdbc/resources/tutorials/understanding-jta/conclusion
https://www.ibm.com/developerworks/cn/java/j-lo-jta/
http://blog.csdn.net/terryzero/article/details/4467739