Version 11

    What is the correct pattern for UserTransaction demarcation

    The correct pattern for working with UserTransactions in the server

    CMT

     

    The simple answer is use CMT. It is very seldom that you need BMT. You are less likely to have errors if you invoke CMT bean(s) with RequiresNew transaction demarcation.

     

    But I need to change the transaction timeout

     

    Different options about how to change the transaction timeout are explained in TransactionTimeout

     

    The correct pattern for working with UserTransactions in the server

     

    Common mistakes are to leave paths through the code where neither commit or rollback is invoked. These paths usually happen when you get an unexpected error.

     

    • Put the commit/rollback in a finally block

    • Catch and rethrow errors where you want to force a rollback

    • You might want to log the errors or map them to some other error

    • You might want to log all rollbacks?

     

    UserTransaction ut = ... // e.g. new InitialContext().lookup("java:comp/UserTransaction");
    ut.begin();
    try
    {
    // DO SOMETHING
    }
    catch (Exception e)
    {
       ut.setRollbackOnly(); // Force a rollback for this error
       throw e;
    }
    finally
    {
       if (ut.getStatus() == Status.STATUS_ACTIVE)
          ut.commit();
       else
          ut.rollback();
    }
    

     

    The correct pattern for working with UserTransactions from remote clients

     

    Common mistakes, again, are to leave paths through the code where neither commit or rollback is invoked but in the case of remote clients, we need to take into account that calls, such as getStatus(), can fail due to connectivity issues. It would be up to the client to decide whether it wants to wait and retry the call first before issuing a rollback() to clear the broken transaction but the important thing is that commit() or rollback() need to be called at the end of transaction, regardless of the outcome.

     

    Assuming that the client did not attempt any retries, the following would be a valid pattern for remote clients:

     

    UserTransaction ut = ... // e.g. new InitialContext().lookup("java:comp/UserTransaction");
    ut.begin();
    try
    {
    // DO SOMETHING
    }
    catch (Exception e)
    {
       ut.setRollbackOnly(); // Force a rollback for this error
       throw e;
    }
    finally
    {
      int status = -1;
      try
      {
        status = tx.getStatus();
      }
      catch(Exception e)
      {
        // log exception calling getStatus()
      }
                
      if (status == Status.STATUS_ACTIVE)
        tx.commit();
      else
        tx.rollback();
    }