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

class Foo {

    @PersistenceContext(unitName="EmployeeService")
    EntityManager em;
    
}

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

class Bar {

    @PersistenceUnit(unitName="EmployeeService")
    EntityManagerFactory emf;
    
    void init() {
        EntityManager em = emf.createEntityManager();
        // or 
        EntityManager em = Persistence.createEntityMnagerFactory("EmployeeService")
                                      .createEntityManager();
    }
    
}

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
@StateFull
class FooExtended {

    @PersistenceContext(unitName="EmployeeService",
                        type=PersistenceContextType.EXTENDED)
    EntityManager em;
    
}

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:

Persistence context collision

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.
em.joinTransaction();

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.

class FooUnsynchronized {

    @PersistenceContext(unitName="EmployeeService",
                        synchronization=UNSYNCHRONIZED)
    EntityManager em;
    
    // or by emf.createEntityManager(UNSYCHRONIZED)
    
}

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.

class BarResourceLocal {

    void method() {
        EntityManager em = ...;
        try{
            em.getTransaction().begin();
            
            Employee employee = em.find(Employee.class, "ff19263d-dee5-430a-9026-027241479a27");
            employee.setFirstName("Bob");
            em.persist(employee);
                        
            em.getTransaction().commit();
        } catch(Exception e) {
            em.getTransaction().rollback();
        }
    }
    
}

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.

Transaction propagation

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.

Transaction propagation - Required

RequiresNew

Always starts a new transaction. Container suspends the client transaction - if any - and back to them after newly created transaction.

Transaction propagation - Required

Mandatory

The container needs active transaction - in the case when there no active transaction found container throws TransactionRequiredException.

Transaction propagation - Mandatory

NotSupported

If there is an active transaction, the container suspends it for the time of method invocation and then resume it after the method.

Transaction propagation - NotSupported

Supports

Nothing happens. The container uses an active transaction, but if there is no transaction, it does not start a new one.

Transaction propagation - NotSupported

Never

Never means the container does not allow any transaction. In the case of an active transaction, it throws RemoteException.

Transaction propagation - NotSupported

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: