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()操作