Thursday, May 05, 2005

Transaction Management Using Sonic XIS Server, Oracle, and Spring

The WorldSync application has three types of transactions that need to be managed:

  • XIS
  • Direct use of Oracle
  • Spring-mediated use of Oracle

Let's look at each transaction type to see how the API is used.

XIS (with synchronized Oracle transactions)

When working with the XIS engine, you should only deal with the org.wwre.xis.transaction.TransactionHelper class. Oracle connections are managed automatically to coincide with XIS actions.

TransactionHelper.getClientSession()
getLocalReadOnlySession()
getLocalUpdateSession()
These three methods return an XIS Session object.
TransactionHelper.commitSession() This method commits XIS and Oracle transactions. If a new Oracle transaction is needed, OracleBootstrap.newTransaction() must be called.
TransactionHelper.releaseSession() This method rolls back both the XIS and Oracle transactions if the XIS transaction has been been commited. Otherwise, it releases the XIS session and closes the Oracle connection.

A typical use of these methods might be:

  Session session = null;

  try {
    ReadWimConfiguration.processUsingDefaults();
    session = TransactionHelper.getLocalReadOnlySession();
    // do some XIS and Oracle work.
    TransactionHelper.commitSession();
  } catch (Exception e) {
    logger.fatal(e, e);
  } catch (Error e) {
    logger.fatal(e, e);
  } finally {
    TransactionHelper.releaseSession();
    System.out.println("Done.");
  }
Direct use of Oracle

If you only need to work with Oracle, you can directly use the OracleBootstrap class.

getConnection() This method needs to be called first. It will setup the DataSource object, if needed. A singleton Connection object is returned which is managed using the methods in OracleBootstrap. Thise connection has the AutoCommit option turned off.
addException() This method is called from within catch} blocks to register than an exception or error occured.
closeConnection() This method closes the Oracle connection and clears any caught exceptions (unless created by the close operation itself).
closeResultSet() This method closes the specified result set. It maskes the capture of exceptions thrown by the close operation.
closeStatement() This method closes the specified statement (prepared or otherwise). It maskes the capture of exceptions thrown by the close operation.
commitConnection() This method commits the connection but does not close it.
getExceptions() This method returns a copy of the collected exceptions.
hasExceptions() This method returns true of any exceptions have been collected.
newTransaction() This method starts a new transaction. It only needs to be called if you want to begin a new transaction after rolling back or commiting.
rollbackConnection() This method rolls back the connection but does not close it.

A typical use of these methods might be:

// The doIt() method does not commit nor rollback. It just handles the 
// low-level SQL and exception handling. 

public static void doIt() {
  Connection con = null;
  PreparedStatement ps = null;
 
  try {
    con = OracleBootstrap.getConnection();
    ps = con.prepareStatement("sql statement");
    // set parameters and execute query.
  } catch (Exception e) {
    OracleBootstrap.addException(e);
  } finally {
    OracleBootstrap.closeStatement(ps);
  }
  if (OracleBootstrap.hasExceptions()) {
    LogConfiguration.message(OracleBootstrap.getExceptions(), "some message");
  }
}

// This driver method need to be aware of the transaction. If an
// no exception occurs, the connection is commited. Otherwise, it
// is rolled back. In the finally clause, the connection is closed.
pubic static void foo() {
  try {
    doIt();
    OracleBootstrap.commitConnection();
  } catch (Exception e) {
    OracleBootstrap.rollbackConnection();
  } catch (Error e) {
    OracleBootstrap.rollbackConnection();
  } finally {
    OracleBootstrap.closeConnection();
}
Spring-mediated use of Oracle

The Spring framework has been around for quite some time. Since WorldSYNC v3.5 is making greater use of Oracle, I've explored existing frameworks instead of expanding the use of our homegrown JDBC-specific classes.

When using Spring has an mediator for Oracle, you should use the OracleBootstrap class. Its use is similar to that shown above except that some of the transaction handling is automated (you don't need to manually call the rollback method when an exception happens).

getDataSource()This method needs to be called first (instead of the getConnection() method). It will setup the DataSource object, if needed and start a new transaction.
addException()This method is called from within catch} blocks to register than an exception or error occured.
closeConnection()This method closes the Oracle connection and clears any caught exceptions (unless created by the close operation itself).
commitConnection()This method commits the connection but does not close it.
getExceptions()This method returns a copy of the collected exceptions.
hasExceptions()This method returns true of any exceptions have been collected.
newTransaction()This method starts a new transaction. It only needs to be called if you want to begin a new transaction after rolling back or commiting.

A typical use of these methods might be:

try {
  ReadWimConfiguration.processUsingDefaults();
  Spring01 a = new Spring01(OracleBootstrap.getDataSource());
  a.makeCachePoolFree("C05");
  OracleBootstrap.commitConnection();
} catch (Exception e) {
  NoOperation.noOp();
} catch (Error e) {
  NoOperation.noOp();
} finally {
  OracleBootstrap.closeConnection();
}

The rollback, if needed, is handled automatically when the connection is closed.