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
No, an EntityManager is NOT thread safe.
Actually they share the same proxy EntityManager which delegates calls to the same persistence context. 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.
The EntityManagerFactory instances, and consequently, Hibernate's SessionFactory instances, are thread-safe.
You can use the @PersistenceContext annotation to inject an EntityManager in an EJB 3.0 client (such as a stateful or stateless session bean, message-driven bean, or servlet). You can use @PersistenceContext attribute unitName to specify a persistence unit by name, as Example 29-13 shows.
To my great surprise (after years of using jpa in spring) 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 jdbc 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 cdi 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 EntityManager
to 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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With