Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java CDI @PersistenceContext and thread safety

Tags:

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

like image 471
auser Avatar asked Jun 16 '12 12:06

auser


People also ask

Is JPA EntityManager thread-safe?

No, an EntityManager is NOT thread safe.

Is PersistenceContext 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.

Is hibernate EntityManager thread-safe?

The EntityManagerFactory instances, and consequently, Hibernate's SessionFactory instances, are thread-safe.

What is @PersistenceContext annotation used for?

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.


2 Answers

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 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

  • Mind thread-safety when injecting EntityManager
  • The EntityManager is not thread-safe
like image 200
Tomasz Nurkiewicz Avatar answered Oct 01 '22 18:10

Tomasz Nurkiewicz


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.

like image 31
polbotinka Avatar answered Oct 01 '22 20:10

polbotinka