import javax.sql.XAConnection; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource; import com.mysql.jdbc.jdbc2.optional.SuspendableXAConnection; import junit.framework.TestCase; /** * TestPinnedXAConnection v 2. * * Written on 2009-08-26 for mysql bug #46925 * * http://bugs.mysql.com/bug.php?id=46925 * * @author Tony Bussieres * */ public class TestPinnedXAConnection extends TestCase { /** * The testcase below simulates a connection pool in a XA environment, * it starts and ends a XA transaction on one connection, * after it prepares and commits the transaction using * another connection returned by the same XA datasource. * * We expect the connection parameter pinGlobalTxToPhysicalConnection to * track the real XAConnection attached to the Xid. * * However the internal map of SuspendableXAConnection is never populated. * The XAConnection isn't tracked correctly. * * Test case : * * 1 - Prepare the datasource * 2 - Generate a fake Xid (to simulate a transaction) * 3 - Getting connection #1 from the datasource * 4 - Start and end a transaction on connection #1 * 5 - Get connection #2 from the same datasource. * 6 - Prepare and commit the transaction on connection #2. * * Step 6 will fail on prepare without the patched driver. The problem is that * the underlying XA connection isn't correctly pinned to the current transaction * * @throws Exception */ public void testXAPinnedConnection() throws Exception { // 1- Prepare the datasource to connect to a simple database. MysqlXADataSource xads1 = new MysqlXADataSource(); xads1.setPinGlobalTxToPhysicalConnection(true); xads1.setUrl("jdbc:mysql://172.16.13.74:4040/TestDB"); xads1.setUser("testuser"); xads1.setPassword("testpass"); xads1.setLogXaCommands(true); // 2 - Generate a fake Xid Xid txid = new MyXid(new byte[] { 0x1 }, new byte[] { 0x1 }); // fake Xid // simulating a connection pool. // 3 - Get connection #1 from the datasource XAConnection c1 = xads1.getXAConnection(); assertTrue(c1 instanceof SuspendableXAConnection); // 4 - Start and end a transaction on connection #1 c1.getXAResource().start(txid, XAResource.TMNOFLAGS); c1.getXAResource().end(txid, XAResource.TMSUCCESS); // 5 - Get connection #2 from the same datasource. XAConnection c2 = xads1.getXAConnection(); assertTrue(c2 instanceof SuspendableXAConnection); // Do the "prepare" on another connection // Since we are using a "pinned" connection we should have the same "currentXAConnection" for both SuspendableXAConnection // 6 - Prepare and commit the transaction on connection #2. c2.getXAResource().prepare(txid); // this will fail without the patch. c2.getXAResource().commit(txid,false); } /** * Fake Xid * @author tbussier * */ class MyXid implements Xid { byte[] gtxid; byte[] brid; public MyXid(byte[] gtxid, byte[] brid) { this.gtxid = gtxid; this.brid = brid; } public byte[] getBranchQualifier() { return brid; } public int getFormatId() { return 0; } public byte[] getGlobalTransactionId() { return gtxid; } } }