JTA事务总结(三)

自:http://blog.sina.com.cn/s/blog_661a3fce0100msjv.html

今天对XA和非XA驱动进行了更进一步的研究,终于搞清了以前些模菱两可的问题。

通过测试得知,在JTA事务中(包括JDBC事务以及非事务环境下),应用程序操作的connection其实都是weblogic的包装类

[A、B]:

weblogic.jdbc.wrapper.JTSConnection_weblogic_jdbc_oracle_OracleConnection

[C、D]:

weblogic.jdbc.wrapper.JTAConnection_weblogic_jdbc_wrapper_XAConnection_weblogic_jdbcx_base_BaseConnectionWrapper

[E]:

weblogic.jdbc.wrapper.JTSConnection_com_mysql_jdbc_Connection



由于XA驱动实现了XAResource的接口,所以能参与完全的2PC协议,保证多资源参与的事务的原子操作。但是非XA驱动没有实现XAResource的接口的接口,无法完全参与2PC协议,所以在分布式事务(即JTA事务)中weblogic实现了非XA驱动的XAResource包装(wrapper),用来模拟(或者说欺骗TM^_^)两步提交,在...\bea\weblogic81\server\lib\weblogic.jar类包中,通过反编译weblogic.jdbc.wrapper.JTSConnection和weblogic.jdbc.wrapperJTSXAResourceImpl类得到如下代码片段:



JTSXAResourceImpl源码片段:
    public int prepare(Xid xid)throws XAException
    {
        if(!jtsConn.getEnable2PC())
            throw new XAException("JDBC driver does not support XA ... );
        else
            return 0;
    }

    public void commit(Xid xid, boolean flag)throws XAException
    {
        ...
        jtsConn.internalCommit();
        ...
    }
    public void rollback(Xid xid)throws XAException
    {
        ...
        jtsConn.internalRollback();
        ...
    }



JTSConnection源码片段:
    public synchronized void internalRollback() throws SQLException
    {
        ...
        connection.rollback();
        ...
        internalClose();
        ...
    }

    public void internalCommit() throws SQLException
    {
        ...
        connection.commit();
        ...
        internalClose();
        ...
    }



可知如果非XA驱动允许两步提交时(enableTwoPhaseCommit),当TransactionManager调用prepare时XAResource包装类只是简单的返回XA_OK(0),当TransactionManager调用commit或rollback时XAResource包装类将代理调用非XA驱动的JDBC connection的commit或rollback,所以如果在commit或rollback出现异常后,应用程序的数据将有可能处于不一致的状态(其实如果XA驱动在TM调用XAResource的commit或者rollback时出错,系统数据也会处于不一致的状态,不过出现这种情况的概率是微乎其微的,如果想搞三步、四步...提交的话,就会进入鸡生蛋、蛋生鸡的无休止讨论的问题了^_^)。



接下来让我们研究一下连接关闭的问题,细心的人也许早已发现JTA与JDBC的事务对于应用层的操作有点“自相矛盾”,JDBC的先获得con在setAutoCommit(false)启动事务,然后关闭con,在commit或者rollback事务,然而JTA的顺序正好相反,先tx.begin(),再获取con,然后关闭con,最后再tx.commit或者rollback。(这里有句话您看完一下内容后会认同的:For both non-XA and XA driver, you can close the connection after the distributed transaction is completed.)

当应用程序调用Connection.close时容器通过注册的ConnectionEventListener事件通知TransactionManager,以便TransactionManager结束Connection对应的XAResource对象的事务分支(end函数调用),对于XA驱动的连接此时在Connection.close之后即可将该连接返回XA连接池供其他业务使用。

所以JTA spec中的提示到:

A distributed transaction may still be active after a participating Connection object is closed. This is not true for local transactions。

但是对于非XA驱动调用Connection.close后的情况将有所有区别,由于XA驱动需要用connection进行最后的commit或rollback,所以应用程序调用Connection.close之后只是对与应用不能再使用包装的Connection,但容器并没有真正将连接返回连接池,而是在调用XAResource包装类的commit和rollback时,进而调用JTSConnection的internalCommit和internalRollback,最终再JTSConnection的这两个函数中internalClose将非XA的连接释放到连接池中。

所以weblogic的资料(http://edocs.bea.com/wls/docs60/faq/transactions.html)中说:
the number of active distributed transactions using the non-XA
connection pool is limited by the maximum capacity of the JDBC connection pool

When you use an XA driver, the connection management is more scalable. WLS does not hold on to the same physical XA connection until the transaction is committed or rolled back. In fact, in most cases, the XA connection as only held for the duration of a method invocation. WLS JDBC wrappers intercept all JDBC calls and enlist the XAResource associated with the XA connection on demand. When the method invocation returns to the caller, or when it makes another call to another server, WLS delists the XAResource associated with the XA connection.

WLS also returns the XA connection to the connection pool on delistment if there are no open result sets. Also, during commit processing, any XAResource object can be used to commit any number of distributed transactions in parallel. As a result, neither the number of active distributed transactions using the XA connection pool nor the number of concurrent commit/rollbacks is limited by the maximum capacity of the connection pool. Only the number of concurrent database access connections is limited by the maximum capacity of the connection pool.


对于以上XA驱动的con在关闭后,不必等待事务结束即释放回连接池的推论,我在weblogic上对oracle做了些好像没有效果,weblogic中有个 Keep XA Connection Till Transaction Complete 的选项我也没有选中啊。不知是我对JTA的理解有误,还是说与我用的数据库驱动或者是weblogic的实现有关,要是有谁测出了效果还请指点指点小弟。

最后请注意:除非将XA驱动的连接池设置允许【Supports Local Transaction】选项,否则在非事务的环境下对con进行的操作将抛出如下错误,甚至是getAutoCommit()操作

猜你喜欢

转载自wokeke.iteye.com/blog/1142954