Transaction not active exception - EJB Transaction State

5.2k views Asked by At

I am having a problem with EJB components that are responsible for starting a transaction. I am using Jboss 5.01.

Basically I would like to execute a given code after a specific transaction was committed. the specific code also involves calling an EJB component which makes it's own transactions.

To make sure that my code is executed after a previous transaction is committed I've registered a Synchronization component into a transaction component :

Transaction tx = transactionManager.getTransaction();
tx.registerSynchronization(new CallbackSynchronization());

The Synchronizaton implementation basically does the following:

class CallbackSynchronization implements Synchnronization {

    private AccountService service;  // This is a Stateless session bean

    public CallbackSynchronization(AccountService service) {
        this.service   = service;
    }

    public afterCompletion(int status) {
        if(Status.STATUS_COMMITTED == status) {
            service.deleteAccounts();
        }
    }
}

Problem is that when I call the service.deleteAccounts() I get an exception that eventually tells me that the transaction is not active.

And this is what confuses me. an EJB with methods marked with @TransactionAttribute(TransactionAttributeType.REQUIRED) will create a new transaction if one is not active(the REQUIRED is the default in JBOSS).

Why then am I getting "Transaction not active" ?

Many Thanks,

Yaniv

1

There are 1 answers

1
Nicholas On BEST ANSWER

The problem is that the original transaction that you started is still associated with the thread (even though it is in a COMMITTED status). One of the significant differences between using the Transaction and the TransactionManager is that the later's commit() and rollback() methods will unassociate the transaction from the thread. To quote from the javadoc for both methods:

When this method completes, the thread is no longer associated with a transaction.

There's two ways to deal with this (and I am outlining them in a very raw manner which you may want to refine a bit).

Option 1: Issue a rollback or commit against the transaction manager (in a try block because it will fail).

public afterCompletion(int status) {
  if(Status.STATUS_COMMITTED == status) {
    try { transactionManager.rollback(); } catch (Throwable t) {}
    service.deleteAccounts();
  }
}

Option 2: Start a new transaction, which will satisfy the REQUIRED attribute of your EJB by pre-starting a transaction, but you need to stick around and manage it which gets sticky.

public afterCompletion(int status) {
  if(Status.STATUS_COMMITTED == status) {
    try { 
      transactionManager.begin();
      service.deleteAccounts();
      transactionManager.commit();
    } catch (Exception e) {
        // ... handle exception here
    }
  }
}

Option 3: The cleanest option may be to mark the EJB method as REQUIRES_NEW as this will force the EJB container to start a new transaction.