Chapter 4. Managing JTA transactions declaratively using the annotations

You can let the container demarcate transaction boundaries by automatically beginning and committing JTA transactions based on annotations. The following chapters demonstrate how you can manage JTA transactions and define transaction boundaries using the @Transactional annotation.

4.1. Defining transaction boundaries declaratively

You can use @Transactional to control transaction boundaries on any CDI bean at the method level or at the class level to ensure that every method is transactional. This also applies to REST endpoints.

Procedure

  • Define the scope of the transaction with the @Transactional annotation on the entry method:

    Example src/main/java/org/acme/SantaClauseService.java

    import javax.inject.Inject;
    import javax.enterprise.context.ApplicationScoped;
    import javax.transaction.Transactional;
    
    @ApplicationScoped
    public class SantaClausService {
    
        @Inject ChildDAO childDAO;
        @Inject SantaClausDAO santaDAO;
    
        @Transactional 1
        public void getAGiftFromSanta(Child child, String giftDescription) {
            // some transaction work
            Gift gift = childDAO.addToGiftList(child, giftDescription);
            if (gift == null) {
                throw new OMGGiftNotRecognizedException(); 2
            }
            else {
                santaDAO.addToSantaTodoList(gift);
            }
        }
    }

    1
    @Transactional annotation defines your transaction boundaries and wraps this call within a transaction.
    2
    When a RuntimeException crosses the transaction boundaries, the transaction manager rolls back the transaction.

4.2. Configuring a transaction for rollback declaratively

Exceptions caused by system-level faults mark the transactions for rollback and abort the transaction immediately. You can override the default behavior using the @Transactional(dontRollbackOn=SomeException.class) or the rollbackOn attribute.

Prerequisites

  • Have a Quarkus Maven project.

Procedure

  • Use the @Transactional(dontRollbackOn=SomeException.class) to specify an exception that does not roll back the transaction:

    Example src/main/java/org/acme/SantaClauseService.java

    import javax.inject.Inject;
    import javax.enterprise.context.ApplicationScoped;
    import javax.transaction.Transactional;
    
    @ApplicationScoped
    public class SantaClausService {
    
        @Inject ChildDAO childDAO;
        @Inject SantaClausDAO santaDAO;
    
        @Transactional(dontRollbackOn=NonCriticalRuntimeException.class)
        public void getAGiftFromSanta(Child child, String giftDescription) throws Exception {
            Gift gift = childDAO.addToGiftList(child);
    
            // might throw a NonCriticalRuntimeException
            gift.setDescription(giftDescription);
    
            santaDAO.addToSantaTodoList(gift);
        }
    }

    In this example, the transaction context is propagated to all calls nested in the @Transactional method (childDAO.addToGiftList() and santaDAO.addToSantaTodoList()). The transaction commits unless a runtime exception crosses the method boundary.

4.3. Configuring a transaction timeout declaratively

Use the @TransactionConfiguration annotation in addition to the @Transactional annotation to specify the timeout in seconds. You can place the @TransactionConfiguration annotation only on the top-level method that delineates the transaction.

Procedure

  • Use the timeout property of the @TransactionConfiguration to set the timeout in seconds:

    import javax.transaction.Transactional;
    
    @Transactional
    @TransactionConfiguration(timeout=40)
    public void getAGiftFromSanta(Child child, String giftDescription) {...}
Note

The configuration defined on a method takes precedence over the configuration defined on a class. When you define @TransactionConfiguration on a class, it is equivalent to defining it on all the methods of the class that are marked with @Transactional.

4.4. Methods returning reactive values

If a method annotated with @Transactional returns a reactive value it does not terminate the transaction until the returned reactive value is terminated. The transaction is marked for rollback when the reactive value terminates with an exception, otherwise the transaction is committed.

Additional resources