The transaction management is one of the most important Java Persistence API aspects if you are using Hibernate or any other JPA provider you should know how valuable transaction management is. The JPA transaction determines when the new, modified or deleted entity is synchronised with a database. Why we need transaction management in the first place? As you know, Java Memory Model is not transactional, so we need to get transactional flow somehow.
What should you know about JPA+Transaction? Let’s get some theory.
The persistence context
There is no way to talk about JPA transaction management without mention Persistence Context. What is the Persistence Context? In short, the Persistence Context is a named session of entities
At the first place, we look at JPA transaction types according to PCTX. There are two main types of transactions: JTA transactions and resource-local transactions. In the case of different entities managers types, JPA has some limitation of using them.
Container managed entity managers - only JTA
Entity Manager Container Proxy before each operation checks persistence context connection to JTA transaction - if there is no connection, it creates a new persistence context and connects it to JTA transaction. When Transaction is over - persistence context goes away.
Application managed entity managers - JTA or resource-local transaction management
One critical remark here - when you use application managed entity managers you should remember about the closing of each entity manager manually.
What is the JTA?
JTA - Java Transaction API - is an API for managing transactions in Java. It has a few crucial steps according to the transaction life-cycle
- Transaction synchronization - the process in which transactions becomes registered in a persistence context
- Transaction association - the moment of persistence context connecting with transaction.
- Transaction propagation - the moment of persistence context sharing.
In application ecosystem may be the only one persistence context connected to the JTA and all entity managers within a transaction must have the same persistence context.
We should consider two types of persistence context here: transaction scoped persistence context and extended scoped persistence context
Transaction scoped persistence context
- it is created with a transaction and destroyed with transaction end
- lazy loaded
- an entity manager is responsible for creating it
- the default propagation type is REQUIRED
- a persistence context is shared between transactions
Extended scoped persistence context
- life-cycle is connected to a state-full bean which had created the Persistence Context
- the new persistence context is created with each transaction
- eager (not lazy-loaded)
- there is a chance for Persistence Context collision
pss, you probably never would like to use it :P
Persistence context collision
If you’ve decided to use extended scoped Persistence Context you should know there is a chance that something calls Persistence Context Collision may happen. What is it? Let’s look at the following diagram:
When may it happen? For example when stateless bean starts some method inside stateful bean with Extended Persistence Context.
What is Application Managed Persistence Context?
Application Managed Persistence Context is just pctx/JTA but manageable manually - it is kind of lower level maintenance for those. How pctx <> transaction
synchronisation looks like here? - in this case, it means that transaction commits flush the Persistence Context, and also there is no limit for such Persistence Contexts but keep in mind that there only one Container Managed Persistence Context maybe be assigned at a time.
It may participate with JTA in two ways:
- When Persistence Context is created within the transaction, the JPA provider automatically synchronises the Persistence Context with that transaction.
- When Persistence Context is created lazily, it is possible to synchronise it manually by
joinTransaction
method.
Little more information…
You should keep in mind following stuff if you would like to use entity managers within some threads flow.
- EntityManager —–> NOT THREAD SAFE
- EntityManagerFactory —–> THREAD SAFE
- em.joinTransaction() may not be called concurrently at the same instance of entity manager
Remember that in the case of Persistence Context synchronisation with a transaction - the changes are still saving to a database after commit even when an Entity Manager would be close.
I need to add one more significant remark here about using multiple Persistence Context is - when you use few Persistence Contexts for the one JTA some problem with data consistency can arise.
What if you wouldn’t like to have Entity Manager synchronised with transaction automatically? You are able then to create UNSYNCHRONIZED (with a transaction) Entity Manager but then you should take care about synchronisation by your own - Entity Manager .joinTransaction method.
Resource Local Transaction
One more type of transaction management exists in JPA ecosystem - Resource Local Transaction. What does it mean? It means that transaction management is 100% by your control. Implementation of it happens with the implementation of javax.persistence.EntityTransaction
. There are some disadvantages of that, for example, you may get IllegalStateException
when some transaction is already started, and you try to start the new one. The same exception is caused in the case of commit or rollback without an active transaction.
Transaction propagation
If you are going to use Hibernate or one of other JPA provider you should be familiar with transaction propagation, so the last topic I would like to describe is Transaction Propagation
, what is it? In short, it is a flow of creating, avoiding and passing transaction from method to method.
In raw JPA We recognise the following types of propagation:
Required
In most cases default propagation level. It means that if there is no active transaction the container starts the new one, otherwise container uses current transaction.
RequiresNew
Always starts a new transaction. Container suspends the client transaction - if any - and back to them after newly created transaction.
Mandatory
The container needs active transaction - in the case when there no active transaction found container throws TransactionRequiredException
.
NotSupported
If there is an active transaction, the container suspends it for the time of method invocation and then resume it after the method.
Supports
Nothing happens. The container uses an active transaction, but if there is no transaction, it does not start a new one.
Never
Never means the container does not allow any transaction. In the case of an active transaction, it throws RemoteException
.
Credits
Thanks for reading I hope you’ve found some interesting knowledge here - I’ll make more posts about JPA in the future for sure.
Some docs to read: