getConnection in UserTransaction returned closed connection after XAResource.commit() failed on same thread

Solution Unverified - Updated

Environment

  • Red Hat JBoss Enterprise Application Platform (EAP)
    • 7.x

Issue

  • When retrying the Usertransaction after javax.transaction.Usertransaction#commit() failed, javax.sql.DataSource#getConnection() returns closed connection in new Usertransaction.

First, Usertransaction failed with the following Error.

WARN  [com.arjuna.ats.jta] (default task-1) ARJUNA016039: onePhaseCommit on < formatId=131077, gtrid_length=29, bqual_length=36, tx_uid=0:ffff7f000001:21fea082:5dc8ed99:f, node_name=1, branch_uid=0:ffff7f000001:21fea082:5dc8ed99:14, subordinatenodename=null, eis_name=java:jboss/datasources/ExampleDS > (LocalXAResourceImpl@6cb4daa9[connectionListener=6a0eecdd connectionManager=36f87501 warned=false currentXid=null productName=H2 productVersion=@PROJECT_VERSION@ (2016-10-31) jndiName=java:jboss/datasources/ExampleDS]) failed with exception XAException.XA_RBROLLBACK: org.jboss.jca.core.spi.transaction.local.LocalXAException: IJ001156: Could not commit local transaction
	at org.jboss.jca.core.tx.jbossts.LocalXAResourceImpl.commit(LocalXAResourceImpl.java:182)
	at com.arjuna.ats.internal.jta.resources.arjunacore.XAOnePhaseResource.commit(XAOnePhaseResource.java:120)
	at com.arjuna.ats.internal.arjuna.abstractrecords.LastResourceRecord.topLevelOnePhaseCommit(LastResourceRecord.java:172)
	at com.arjuna.ats.arjuna.coordinator.BasicAction.onePhaseCommit(BasicAction.java:2386)
	at com.arjuna.ats.arjuna.coordinator.BasicAction.End(BasicAction.java:1497)
	at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:96)
	at com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:162)
	at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1287)
	at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:126)
	at com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.commit(BaseTransactionManagerDelegate.java:94)
	at org.wildfly.transaction.client.LocalTransaction.commitAndDissociate(LocalTransaction.java:75)
	at org.wildfly.transaction.client.ContextTransactionManager.commit(ContextTransactionManager.java:71)
	at org.wildfly.transaction.client.LocalUserTransaction.commit(LocalUserTransaction.java:53)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.jboss.weld.util.reflection.Reflections.invokeAndUnwrap(Reflections.java:410)
	at org.jboss.weld.bean.builtin.CallableMethodHandler.invoke(CallableMethodHandler.java:42)
	at org.jboss.weld.bean.proxy.EnterpriseTargetBeanInstance.invoke(EnterpriseTargetBeanInstance.java:56)
	at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:106)
	at org.jboss.weldx.transaction.UserTransaction$$Proxy$_$$_Weld$Proxy$.commit(Unknown Source)
	at com.example.HelloServlet.doGet(HelloServlet.java:65)

After that, when retrying Usertransaction and javax.sql.DataSource#getConnection() on same thread, application got the closed connection.

e.g. (the detail of SQLException depends on the JDBC vendor.)

org.h2.jdbc.JdbcSQLException: The object is already closed [90007-193]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
	at org.h2.message.DbException.get(DbException.java:179)
	at org.h2.message.DbException.get(DbException.java:155)
	at org.h2.message.DbException.get(DbException.java:144)
	at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1480)
	at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1458)
	at org.h2.jdbc.JdbcConnection.createStatement(JdbcConnection.java:202)
	at org.jboss.jca.adapters.jdbc.WrappedConnection$1.produce(WrappedConnection.java:357)
	at org.jboss.jca.adapters.jdbc.WrappedConnection$1.produce(WrappedConnection.java:355)
	at org.jboss.jca.adapters.jdbc.SecurityActions.executeInTccl(SecurityActions.java:97)
	at org.jboss.jca.adapters.jdbc.WrappedConnection.createStatement(WrappedConnection.java:355)
	at com.example.HelloServlet.doGet(HelloServlet.java:59)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:686)

Resolution

Close the connection properly before javax.transaction.Usertransaction.commit() as in the following example.

e.g.

javax.transaction.UserTransaction userTransaction = ... // get user transaction here

userTransaction.begin();

java.sql.Connection conn = dataSource.getConnection();
try {
    java.sql.Statement stmt = conn.createStatement();
    try {
        stmt.executeUpdate("...");
    } finally {
        stmt.close();
    }
} finally {
    conn.close(); // close connection before commit
}

userTransaction.commit();

This issue is resolved as part of:

Root Cause

Components
Category

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.