Using Transactions in Quarkus
You don’t need to worry about setting it up most of the time as extensions needing it will simply add it as a dependency.Hibernate ORM for example will include the transaction manager and set it up properly.
You might need to add it as a dependency explicitly if you are using transactions directly without Hibernate ORM for example.Add the following to your :
You can define your transaction boundaries the easy way, or the less easy way :)
The easiest way to define your transaction boundaries is to use the @Transactional
annotation on your entry method (javax.transaction.Transactional
).
@Transactional
can be used to control transaction boundaries on any CDI bean at the method level or at the class level to ensure every method is transactional.That includes REST endpoints.
You can control whether and how the transaction is started with parameters on @Transactional
:
@Transactional(REQUIRES_NEW)
: starts a transaction if none was started ; if an existing one was started, suspends it and starts a new one for the boundary of that method.@Transactional(MANDATORY)
: fails if no transaction was started ; works within the existing transaction otherwise.@Transactional(SUPPORTS)
: if a transaction was started, joins it ; otherwise works with no transaction.@Transactional(NOT_SUPPORTED)
: if a transaction was started, suspends it and works with no transaction for the boundary of the method ; otherwise works with no transaction.
REQUIRED
or NOT_SUPPORTED
are probably the most useful ones.This is how you decide whether a method is to be running within or outside a transaction.Make sure to check the JavaDoc for the precise semantic.
The transaction context is propagated to all calls nested in the method as you would expect (in this example childDAO.addToGiftList()
and santaDAO.addToSantaTodoList()
).The transaction will commit unless a runtime exception crosses the method boundary.You can override whether an exception forces the rollback or not by using @Transactional(dontRollbackOn=SomeException.class)
(or rollbackOn
).
You can also programmatically ask for a transaction to be marked for rollback.Inject a TransactionManager
for this.
Extended configuration of the transaction is possible with the use of the @TransactionConfiguration
annotation that is set in addition to the standard @Transactional
annotation on your entry method or at the class level.
The @TransactionConfiguration
annotation allows to set a timeout property, in seconds, that applies to transactions created within the annotated method.
This annotation may only be placed on the top level method delineating the transaction.Annotated nested methods once a transaction has started will throw an exception.
If defined on a class, it is equivalent to defining it on all the methods of the class marked with @Transactional
.The configuration defined on a method takes precedence over the configuration defined on a class.
If your @Transactional
-annotated method returns a reactive value, such as:
CompletionStage
(from the JDK)(from Reactive-Streams)
Any type which can be converted to one of the two previous types using Reactive Type Converters
This allows your reactive methods to keep on working on the transaction asynchronously until theirwork is really done, and not just until the reactive method returns.
If you need to propagate your transaction context across your reactive pipeline, please see theContext Propagation guide.
The less easy way is to inject a UserTransaction
and use the various transaction demarcation methods.
You can configure the default transaction timeout, the timeout that applies to all transactions managed by the transaction manager, via the property quarkus.transaction-manager.default-transaction-timeout
, specified as a duration.
The default value is 60 seconds.
Yep, it works in your Quarkus application, in your IDE, in your tests, because all of these are Quarkus applications.JTA has some bad press for some people.I don’t know why.Let’s just say that this is not your grand’pa’s JTA implementation.What we have is perfectly embeddable and lean.
Does it do 2 Phase Commit and slow down my app?
No, this is an old folk tale.Let’s assume it essentially comes for free and let you scale to more complex cases involving several datasources as needed.
I don’t need transaction when I do read only operations, it’s faster.
Wrong.First off, just disable the transaction by marking your transaction boundary with
@Transactional(NOT_SUPPORTED)
(orNEVER
orSUPPORTS
depending on the semantic you want).Second, it’s again fairy tale that not using transaction is faster.The answer is, it depends on your DB and how many SQL SELECTs you are making.No transaction means the DB does have a single operation transaction context anyways.Third, when you do several SELECTs, it’s better to wrap them in a single transaction because they will all be consistent with one another.Say your DB represents your car dashboard, you can see the number of kilometers remaining and the fuel gauge level.By reading it in one transaction, they will be consistent.If you read one and the other from two different transactions, then they can be inconsistent.It can be more dramatic if you read data related to rights and access management for example.Why do you prefer JTA vs Hibernate’s transaction management API
It’s a mess because I don’t know if my JPA persistence unit is using
JTA
orResource-level
Transaction