Tuesday, January 10, 2012

Programmatic Transaction Demarcation : ATG


At times, you might need to demarcate transactions in your code. Generally, you should use programmatic demarcation as little as possible, as it is error-prone and can interfere with the application server’s own transaction demarcation mechanisms. If you find it necessary to use programmatic demarcation, you must be very careful to ensure that your code handles any unexpected errors and conditions.

The ATG platform includes two classes that you can use to demarcate transactions in code:

atg.dtm.UserTransactionDemarcation can be used by J2EE components and Nucleus components to perform basic transaction demarcation. This class accesses the UserTransaction object to perform its operations.

atg.dtm.TransactionDemarcation can be used by Nucleus components to demarcate areas of code at a fine granularity. J2EE components cannot use this class, because it accesses the TransactionManager object directly.

Using the UserTransactionDemarcation Class

The following example illustrates how to use the UserTransactionDemarcation class:

UserTransactionDemarcation td = new UserTransactionDemarcation ();
try {
  try {
    td.begin ();


    ... do transactional work ...
  }
  finally {
    td.end ();
  }
}
catch (TransactionDemarcationException exc) {
  ... handle the exception ...
}

There are a few things to note about using the UserTransactionDemarcation class:

The begin() method implements the REQUIRED transaction mode only. If there is no transaction in place, it creates a new one; but if a transaction is already in place, that transaction is used.

If begin() creates a new transaction, the end() method commits that transaction, unless it is marked for rollback only. In that case, end() rolls it back. However, if begin() does not create a transaction (because there is already a transaction in place), end() does nothing.

The code must ensure that end() is always called, typically by using a finally block.

begin() and end() can throw exceptions of class atg.dtm.TransactionDemarcationException. The calling code should log or handle these exceptions.

Using the TransactionDemarcation Class

The following example illustrates using the TransactionDemarcation class:

TransactionManager tm = ...
TransactionDemarcation td = new TransactionDemarcation ();
try {
  try {
    td.begin (tm, td.REQUIRED);


    ... do transactional work ...
  }
  finally {
    td.end ();
  }
}
catch (TransactionDemarcationException exc) {
  ... handle the exception ...
}

There are a few things to note about using the TransactionDemarcation class:

The begin() method takes two arguments. The first argument is the TransactionManager object. The second argument specifies one of the 6 transaction modes: REQUIRED, REQUIRES_NEW, SUPPORTS, NOT_SUPPORTED, MANDATORY, or NEVER. If the second argument is not supplied, it defaults to REQUIRED.

The code must ensure that the end() method is always called, typically by using a finally block.

The begin() and end() methods can throw exceptions of class atg.dtm.TransactionDemarcationException. The calling code should log or handle these exceptions.

The TransactionDemarcation class takes care of both creating and ending transactions. For example, if the TransactionDemarcation object is used with a RequiresNew transaction mode, the end() call commits or rolls back the transaction created by the begin() call. The application is not expected to commit or rollback the transaction itself.

If for some reason the application needs to force the transaction to end, this can be done by calling the TransactionManager.commit() method:


TransactionManager tm = ...
TransactionDemarcation td = new TransactionDemarcation ();
try {
  try {
    td.begin (tm);


    ... do transactional work ...


    tm.commit ();
  }
  catch (RollbackException exc) { ... }
  catch (HeuristicMixedException exc) { ... }
  catch (HeuristicRollbackException exc) { ... }
  catch (SystemException exc) { ... }
  catch (SecurityException exc) { ... }
  catch (IllegalStateException exc) { ... }
  finally {
    td.end ();
  }
}
catch (TransactionDemarcationException exc) {
  ... handle the exception ...
}

Ending a transaction in this way should be avoided wherever possible, because handling all exceptions introduces a lot of complexity in the code. The same result can usually be accomplished by more standard means.

No comments:

Popular Posts