JTA事务总结(三)

lay 2011-08-08

自: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源码片段:

publicintprepare(Xidxid)throwsXAException

{

if(!jtsConn.getEnable2PC())

thrownewXAException("JDBCdriverdoesnotsupportXA...);

else

return0;

}

publicvoidcommit(Xidxid,booleanflag)throwsXAException

{

...

jtsConn.internalCommit();

...

}

publicvoidrollback(Xidxid)throwsXAException

{

...

jtsConn.internalRollback();

...

}

JTSConnection源码片段:

publicsynchronizedvoidinternalRollback()throwsSQLException

{

...

connection.rollback();

...

internalClose();

...

}

publicvoidinternalCommit()throwsSQLException

{

...

connection.commit();

...

internalClose();

...

}

可知如果非XA驱动允许两步提交时(enableTwoPhaseCommit),当TransactionManager调用prepare时XAResource包装类只是简单的返回XA_OK(0),当TransactionManager调用commit或rollback时XAResource包装类将代理调用非XA驱动的JDBCconnection的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。(这里有句话您看完一下内容后会认同的:Forbothnon-XAandXAdriver,youcanclosetheconnectionafterthedistributedtransactioniscompleted.)

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

所以JTAspec中的提示到:

AdistributedtransactionmaystillbeactiveafteraparticipatingConnectionobjectisclosed.Thisisnottrueforlocaltransactions。

但是对于非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)中说:

thenumberofactivedistributedtransactionsusingthenon-XA

connectionpoolislimitedbythemaximumcapacityoftheJDBCconnectionpool

WhenyouuseanXAdriver,theconnectionmanagementismorescalable.WLSdoesnotholdontothesamephysicalXAconnectionuntilthetransactioniscommittedorrolledback.Infact,inmostcases,theXAconnectionasonlyheldforthedurationofamethodinvocation.WLSJDBCwrappersinterceptallJDBCcallsandenlisttheXAResourceassociatedwiththeXAconnectionondemand.Whenthemethodinvocationreturnstothecaller,orwhenitmakesanothercalltoanotherserver,WLSdeliststheXAResourceassociatedwiththeXAconnection.

WLSalsoreturnstheXAconnectiontotheconnectionpoolondelistmentiftherearenoopenresultsets.Also,duringcommitprocessing,anyXAResourceobjectcanbeusedtocommitanynumberofdistributedtransactionsinparallel.Asaresult,neitherthenumberofactivedistributedtransactionsusingtheXAconnectionpoolnorthenumberofconcurrentcommit/rollbacksislimitedbythemaximumcapacityoftheconnectionpool.Onlythenumberofconcurrentdatabaseaccessconnectionsislimitedbythemaximumcapacityoftheconnectionpool.

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

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

相关推荐