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); } } }
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()
andsantaDAO.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) {...}
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