Is a javax.persistence.EntityManager thread safe to be an instance variable?

Is a javax.persistence.EntityManager thread safe to be an instance variable?

In a JPA based DAO class, we usually declare an EntityManager as an instance variable annotated with @PersistenceContext, and use it in the methods of the class. This usage seems to work fine and I just accepted it without further thinking. But recently it turned into a question when I was working on some JPA code that, how could an entity manager be thread safe as an instance variable, while an entity manager does not seem to be meant for sharing among multiple threads?

Usually to such a question, the best place to go for the answer is the specification, which in this case is JSR-317. The answer can be found in Chapter 7 Entity Managers and Persistence Contexts.

Entity managers manage entities within persistence contexts.

Depending on how the transaction type of a persistence unit is configured in persistence.xml, entity managers from the persistence unit can be JTA or resource-local.

  1. JTA entity managers participate in the current JTA transactions, which can span multiple resources and are controlled external to the entity managers.
  2. Resource-local entity managers are unaware of JTA transactions or other resources. They use EntityTransaction to control transactions over the underlying resources mapped by persistence providers. Usually, an entity transaction is mapped to a database transaction.

Depending on how they are obtained, entity managers can be application-managed or container-managed.

  1. Application-managed entity managers are always obtained from EntityManagerFactory#createEntityManager on entity manager factories which are thread safe, where the entity manager factories themselves can either be obtained from Persistence#createEntityManagerFactory or from within a container through @PersistenceUnit.
    • The lifecycles of such entity managers must be managed explicitly through EntityManager#close, etc.
    • Application-managed entity managers can be either JTA or resource-local. If an application-managed entity manager is a JTA entity manager, EntityManager#joinTransaction can be called to join in the current JTA transaction; If an application-managed entity manager is resource-local, just use EntityTransaction.
    • An application-managed entity manager manages an isolated persistence context created with the creation of the application-managed entity manager.
    • Application-managed entity managers are not required to be thread safe and must not be shared among multiple concurrently executing threads. Thus they had better not be instance variables.
  2. Container-managed entity managers are obtained from dependency injection through @PersistenceContext.
    • The lifecycles of container-managed entity managers are always managed automatically by containers.
    • A container-managed entity manager must be a JTA entity manager.
    • A container-managed entity manager effectively has an additional layer on top of an entity manager obtained from EntityManagerFactory#createEntityManager to transparently allow different container-managed entity managers from the same entity manager factory to manage the same persistence context, instead of isolated ones. This is to serve the typical need of business logic across multiple components wanting to participate in a single JTA transaction hence sharing a single persistence context, and is usually implemented by tying lazily initialized persistence contexts to JTA transactions where container-managed entity managers find the persistence contexts they manage through the current JTA transactions. Such persistence contexts are called container-managed persistence contexts, and they are propagated with JTA transactions in local environments. Depending on how long they live, container-managed persistence contexts can be transaction-scoped or extended.
      1. A transaction-scoped persistence context, which is the default, can only live as long as a JTA transaction. When the JTA transaction ends, entities that were managed in the persistence context become detached.
      2. An extended persistence context is associated with a contain-managed entity manager bound to a stateful session bean with the type set to PersistenceContextType#EXTENDED. The persistence context can live as long as the stateful session bean, and can participate in multiple JTA transactions during the lifetime of the session bean. One thing to note, however, is that at most one container-managed persistence context can be propagated with a JTA transaction. Since an extended persistence context is always propagated whenever there is a JTA transaction, the JTA transaction cannot be propagating another persistence context, or there will be an exception.
    • When there is no JTA transaction,
      1. Calling one of the "write" methods, i.e., persist, merge, remove, and refresh, on a container-managed entity manger throws a TransactionRequiredException.
      2. Entities loaded through "read" methods are detached entities.

So in our usual use case, the instance variables are container-managed entity managers. They all manage the same transaction-scoped persistence context in the current JTA transaction of the current thread, thus safe to be instance variables in a specification compliant container, such as EJB and Spring.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.

More information about formatting options

To prevent automated spam submissions leave this field empty.