Search code examples
jakarta-eejbosstransactionscdijava-ee-7

JEE Transactional: where to specify dontRollbackOn / rollbackOn


I have a question regarding the usage of rollbackOn and dontRollbackOn of the JEE transactional annotation. I did some rearch however only found general information on the topic)

@Transactional(dontRollbackOn = {SomeRuntimeException.class}

Where can/must I specify the annotations? Two options make sense to me so which one is it?

  1. In the class the RuntimeException occurs
  2. The "sticky" approach - when the transaction is created (in my case with Requires_new) and once the transaction was annoted it will react accordingly doesn't matter when/where the exception occurs

I would really like the 2nd version since I create a new Transaction which is "handed down" through be business layer to the database related classes. A specific database method is used by two different business functions and only one wants the "dontRollbackOn" function.

However currently in my case (JBOSS 7 EAP, JEE7, Java 1.8) only version 1 works. I need to anotate the method where I do the actual DB query...

@Transactional(dontRollbackOn = {SomeRuntimeException.class}
public void doSomething(){
 ...
 Query query = this.getEntityManager().createQuery(...);
 query.setParameter(...);
 queryResult = query.getSingleResult();
}

Can somebody share some light on this?


Solution

  • Unfortunately you need to do it on the EJB method that throws the exception. Otherwise the exception propagation will mark the transaction for rollback at the method call boundary. So it is answer (1) from your post.

    Some further advice:

    The best way to deal with unexpected exceptions is to let them bubble out and deal with them somewhere near the UI boundary. As they are unexpected you don't normally want any transactions to commit because that will leave your application in an inconsistent state.

    However, your sample code provides a case where exceptions may actually be expected. In this case you should deal with them in the originating method:

    try {
        Query query = this.getEntityManager().createQuery(...);
        query.setParameter(...);
        queryResult = query.getSingleResult();    
        ...
    } catch (NoResultException e) {
        // What are the business rules when NoResultException happens?
    } catch (NonUniqueResultException e) {
        // What are the business rules when NonUniqueResultException happens?
    }
    

    If one or both are actually unexpected then paragraph one still applies.