21

Is an EntityManager @Inject[ed] as follows in muliple classes threadsafe?

@PersistenceContext(unitName="blah")
private EntityManager em;

This question and this one seem to be Spring specific. I am using Jave EE CDI services

Community
  • 1
  • 1
auser
  • 6,307
  • 13
  • 41
  • 63

3 Answers3

22

To my great surprise (after years of using in ) EntityManager is not thread safe. This is actually understandable if you think about it deeper: EntityManager is just a wrapper around native JPA implementation, e.g. session in Hibernate, which in turns is a wrapper around connection. That being said EntityManager can't be thread safe as it represents one database connection/transaction.

So why does it work in Spring? Because it wraps target EntityManager in a proxy, in principle using ThreadLocal to keep local reference per each thread. This is required as Spring applications are built on top of singletons while EJB uses object pool.

And how can you deal with that in your case? I don't know but in EJB each stateless and stateful session bean is pooled, which means you cannot really call method of the same EJB from multiple threads in the same time. Thus EntityManager is never used concurrently. That being said, injecting EntityManager is safe, at least into stateless and stateful session beans.

However injecting EntityManagerto servlets and singleton beans is not safe as possibly several threads can access them at the same time, messing up with the same JDBC connection.

See also

Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • 4
    Nice explanation, but you are wrong when stating "in EJB each session bean is pooled, which means you cannot really call method of the same EJB from multiple threads on the same time" - @Singleton EJB or EJB with pool of size 1, which has bean managed concurrency can have multiple threads executing EJBs logic simultaneously. – Stevo Slavić Jun 25 '12 at 13:56
  • @StevoSlavić: well, I am actually saying "*injecting EntityManager to [...] singleton beans is not safe*". I will clarify that part if singletons are also considered session beans. But can you actually disable container managed synchronization for stateless and stateful session beans? I know you can do it only for singletons... – Tomasz Nurkiewicz Jun 25 '12 at 13:59
11

Although EntityManager implementations itself are not thread safe the Java EE container injects a proxy which delegates all methods invocations to a transaction bound EntityManager. Therefore each transaction works with it's own EntityManager instance. This is true for at least transaction-scoped persistence context (which is default).

If container would inject a new instance of EntityManager in each bean the below wouldn't work:

@Stateless
public class Repository1 {
   @EJB
   private Repository2 rep2;

   @PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION)
   private EntityManager em;

   @TransactionAttribute
   public void doSomething() {
      // Do something with em
      rep2.doSomethingAgainInTheSameTransaction();
   }
}

@Stateless
public class Repository2 {
   @PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION)
   private EntityManager em;

   @TransactionAttribute
   public void doSomethingAgainInTheSameTransaction() {
      // Do something with em
   }
}

doSomething->doSomethingAgainInTheSameTransaction call happens in a single transaction and therefore the beans must share the same EntityManager. Actually they share the same proxy EntityManager which delegates calls to the same persistence context.

So you are legal use EntityManager in singleton beans like below:

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class Repository {
   @PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION)
   private EntityManager em;
}

Another proof is that there is no any mention of thread safety in EntityManager javadoc. So while you stay inside Java EE container you shouldn't care about concurrency access to EntityManager.

polbotinka
  • 488
  • 6
  • 7
  • 3
    Note that this answer is (despite being accepted) in fact not true, as polbotinka mentioned in another answer. Continue reading if you're interested in `thread safety` with `Java EE EntityManager`. – Menno Apr 11 '13 at 14:06
  • @Aquillo, "in fact not true" is incorrect and polbotinka didn't mention it. This answer is factually correct and to the point. The only nitpick I could think of is that it applies significance to proxy identity ("Actually they share the same proxy EntityManager") which is meaningless. – Vsevolod Golovanov Mar 13 '18 at 19:52
  • polbotinka talks about EJB, but question was about CDI! – guest Oct 01 '18 at 18:26
8

I feel I need to go deeper into this because my first answer was not absolutely true.

I will refer to JSR-220 (EJB 3.0). In section 5.2 Obtaining an EntityManager you may find:

An entity manager may not be shared among multiple concurrently executing threads. Entity managers may only be accessed in a single-threaded manner.

Well that's it. You may stop reading here and never use EntityManager in singleton beans unless properly synchronized.

But I believe there is a confusion in the spec. There are actually two different EntityManager implementations. The first is one is provider implementation (saying Hibernate) which is not obliged to be threadsafe.

On the other hand there is a container implementation of EntityManager. Which is also not supposed to be threadsafe according to the above. But container's implementation acts as a proxy and delegates all calls to the real provider's EntityManager.

So further in the spec in 5.9 Runtime Contracts between the Container and Persistence Provider:

For the management of a transaction-scoped persistence context, if there is no EntityManager already associated with the JTA transaction: The container creates a new entity manager by calling EntityManagerFactory.createEntityManager when the first invocation of an entity manager with Persistence- ContextType.TRANSACTION occurs within the scope of a business method executing in the JTA transaction.

This means in turn that there will be a different EntityManager instance for each transaction started. The code that creates an EntityManager is safe according to 5.3:

Methods of the EntityManagerFactory interface are threadsafe.

But what if there is an EntityManager associated with JTA transaction? The code that binds an EntityManager associated with current JTA transaction may be not threadsafe according to the spec.

But I can't really think of an application server implementation that works correctly with EntityManager injected into stateless beans and not correctly within singletons.

So my conclusions are:

  1. If you want to follow the JSR-220 strictly then never use EntityManager in singletons until synchronizing the access to it.
  2. I personally will continue to use EntityManager in singleton because my application server implementation works perfectly with it. You may want to check your implementation before doing so.
Eugen Labun
  • 2,561
  • 1
  • 22
  • 18
polbotinka
  • 488
  • 6
  • 7
  • what application server are you referring to in your conclusion point 2? – brain storm Dec 01 '14 at 22:57
  • 3
    probably you can use perfectly thread safe your Em in Singleton EJB because you leave the basic Singleton behaviour for all its methods (Lock.Write) which lets all the methods reachable as they have had a synchronized modifier. – Black.Jack Aug 06 '17 at 18:36
  • "On the other hand there is a container implementation of EntityManager. Which is also not supposed to be threadsafe according to the above." - you're misreading the spec. The spec doesn't concern itself with proxies here, it talks about a an actual logical EntityManager, not each physical java instance that extends the EntityManager class. The spec could be clearer though. They probably didn't want to go far into "contextual proxies" territory, just implied it with "transaction-scoped". – Vsevolod Golovanov Mar 13 '18 at 19:45
  • In the same vein I doubt that "The code that binds an EntityManager associated with current JTA transaction may be not threadsafe according to the spec" is a correct conclusion. – Vsevolod Golovanov Mar 13 '18 at 19:47
  • @Black.Jack I agree, but for those that are considering doing this make sure you understand the performance impact. With a write-locked Singleton using the database, this means only one user can use it a time, so if you really want to do this, make sure you're not running frequent, expensive queries. That said, I can't imagine why you'd want to do it when Stateless EJBs will eliminate most concurrency and performance concerns. – DavidS Oct 11 '19 at 23:59