Tuesday, September 11, 2007

Container Managed Transactions in EJB

Be careful when using more "advanced" transaction configurations in EJB. Yesterday, we spent quite some time investigating the reason why calling a bean method marked with the RequiresNew TX attribute, did NOT spawn a separate TX context.


class SomeSessionBean implements SomeSession {
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void helperMethod() {
// must perform some update in separate TX
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void mainMethod() {
this.helperMethod();
}
}


The code flows into mainMethod(), and that was expected to perform helperMethod() in another transaction. A simple test case and a debugging run clearly showed that only the original transaction was used in the entire flow.

What happened? The container does NOT intercept the second method invocation, so it cannot create a new transaction. One way to solve it, is doing some JNDI lookup (EJB2) or performing a EJB injection (EJB3). Both workaround will work as intended, but have one drawback: pollution of the original API with implementation "details".

IMHO the better solution: define a separate helper bean containing the helper methods. It requires some framework code in EJB2, but when you are "blessed" by EJB3, it can provide you a rather elegant solution, where the front session bean, delegates logic within a separate TX to another bean.

In case you need much more complexity, it may be better to use bean managed transactions, but I recommend to try this first. The bottom line: keep a close watch on transaction attributes of EJB session beans, and be aware of the existence, or the opposite, of the surrounding container!