Oracle FAQ | Your Portal to the Oracle Knowledge Grid |
Home -> Community -> Usenet -> c.d.o.server -> How to end pending transactions with jdbc
Hi,
I use the oracle.jdbc.xa package to controll transactions. The normal usage works fine but if I simulate a "crash" after a transaction has been prepared I cannot end this transaction later on due to a the XAException "The XID is not valid". (Accessing a 8.1.7 Oracle server with the 8.1.7 JDBC thin driver)
I use the class below to test this and the error occurs only if I wait for a while between the two executions ("prepare" and "end").
If I execute 'java XARecovery "prepare"' and directly afterwards 'java XARecovery "end"' everything works fine and the transaction is rolled back. So I conclude that the xid and test program itself cannot be that faulty.
If I wait inbetween for about a minute the execution of 'java XARecovery "end"' is unsuccessfull. The invocation of xaRes.rollback(xid); throws the XAException "The XID is not valid". Precisely I get the following output:
XA Error is -4
XA Error message The XID is not valid.
SQL Error is 24756
oracle.jdbc.xa.OracleXAException
at oracle.jdbc.xa.OracleXAResource.checkError(OracleXAResource.java:498) at oracle.jdbc.xa.client.OracleXAResource.rollback(OracleXAResource.java:617) at XARecovery.main(XARecovery.java:85)
I find an entry in the view SYS.DBA_PENDING_TRANSACTIONS with exactly the same information (formatid.globaltransactionid and branchid) like the xid in my test program. (What I checked by using the XAResource recover method and comparing the recovered xid with the created one)
Why can't the transaction be rolled back then???
Thanks for your help,
Matthias
/*
Test to use one Xid for a transaction that gets prepared in a first
run and
ended only in a second run.
I use it like this (obviously with the oracle driver in the classpath)
java XARecovery "prepare"
java XARecovery "end"
*/
import java.sql.*;
import javax.sql.*;
import oracle.jdbc.driver.*; import oracle.jdbc.pool.*; import oracle.jdbc.xa.OracleXid; import oracle.jdbc.xa.OracleXAException; import oracle.jdbc.xa.client.*;
class XARecovery
{
// the connection data is secret of course
private static final String db_url = "jdbc:oracle:thin:@..."; private static final String db_username = "..."; private static final String db_password = "..."; public static void main (String args []) throws SQLException { Connection helpConn = null; Statement helpStmt = null; XAConnection xaConn = null; Connection conn1 = null; XAResource xaRes = null; try { DriverManager.registerDriver(new OracleDriver()); helpConn = DriverManager.getConnection (db_url, db_username, db_password); helpStmt = helpConn.createStatement ();prp);
// Create the Xid
Xid xid = createXid(8, 1);
// Create a XADataSource instance
OracleXADataSource oxds = new OracleXADataSource(); oxds.setURL(db_url); oxds.setUser(db_username); oxds.setPassword(db_password);
// Get a XA connection to the underlying data source
xaConn = oxds.getXAConnection(); conn1 = xaConn.getConnection(); xaRes = xaConn.getXAResource(); if (args[0].equals("prepare")){ // prepare the test table try { helpStmt.execute ("drop table my_table"); } catch (SQLException e) { } try { helpStmt.execute ("create table my_table (col1 int)"); } catch (SQLException e) { } // Start a Tx, do something, end it xaRes.start(xid, XAResource.TMNOFLAGS); DoSomeWork (conn1); xaRes.end(xid, XAResource.TMSUCCESS); // do the 2PC prepare int prp = xaRes.prepare (xid); System.out.println("Return value of prepare is " +
} else if (args[0].equals("end")){ // I could call the xaRes.recovery() method to get the // xid again, but I have a fixed one anyway xaRes.rollback(xid); System.out.println("Transaction rolled back."); } } catch (SQLException sqe) { sqe.printStackTrace(); } catch (XAException xae) { if (xae instanceof OracleXAException) { System.out.println("XA Error is " + ((OracleXAException)xae).getXAError()); System.out.println("XA Error message " + ((OracleXAException)xae).getXAErrorMessage(((OracleXAException)xae).getXAError())); System.out.println("SQL Error is " + ((OracleXAException)xae).getOracleError()); } } finally {
// Close connections
if (helpStmt != null) helpStmt.close(); if (helpConn != null) helpConn.close(); if (conn1 != null) conn1.close(); if (xaConn != null) xaConn.close(); }
static Xid createXid(int gids, int bids)
throws XAException
{
byte[] gid = new byte[1]; gid[0]= (byte) gids; byte[] bid = new byte[1]; bid[0]= (byte) bids; byte[] gtrid = new byte[64]; byte[] bqual = new byte[64]; System.arraycopy (gid, 0, gtrid, 0, 1); System.arraycopy (bid, 0, bqual, 0, 1); Xid xid = new OracleXid(0x1234, gtrid, bqual); return xid;
private static void DoSomeWork (Connection conn)
throws SQLException
{
// Insert 4321 into my_table Statement stmt = conn.createStatement (); int cnt = stmt.executeUpdate ("insert into my_table values (4321)"); System.out.println("No of rows Affected " + cnt); stmt.close(); stmt = null;