Today I discovered some unexpected behaviour in EJB. I've got MDB with default transaction attribute (REQUIRED
) and SLSB with transaction attribute set to REQUIRES_NEW
. My MDB calls the SLSB and catch any exception that SLSB can throw. When something realy bad occurres in the SLSB and some subclass of RuntimeException
was thrown. Then new transaction, which was created for the SLSB, became marked for rollback. It is a correct behaviour from my point of view. Then MDB catch this exception and perform some action (write a message to log, for example) withour rethrow. But the MDB transaction somehow became marked for rollback too, which seems strange to me. Is this behaviour correct?
To be more precise I can write some code similar to actual one, that produce this behaviour:
@MessageDriven
public class A{
@EJB
private B b;
@Overried
public void onMessage(Message msg){
...
try{
b.process(msg);
} catch (Throwable t){
logger.error("Something gone wrong",t);
}
...
}
And SLSB looks like this:
@EJB
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class B{
public void process(Message msg){
...
}
}
Problematic task flow looks like this:
- Message driven bean
onMessage(Message)
was called. - Message driven bean perform some actions successful and then invoke
B.process(Message)
method. - Something bad in
B
occurred andRuntimeException
was thrown. RuntimeException
was wrapped inEJBException
and was successfully catched by message driven bean.- Message driven bean
onMessage(Message)
method was executed completely, but its transaction was marked for rollback.
Can anybody explain this behaviour? Thanks in advance.