javamultithreadingjpaglassfish-4

Is EntityManager really thread-safe?


I'm talking about the basic usage here:

@Stateless
public class BookServiceBean implements BookService {
  @PersistenceContext EntityManager em;
  public void create(Book book) { this.em.persist(book);}
} 

Googling the above question, StackOverflow says yes, but no - the accepted answer says Yes, but a followup is No; Spring.io says both yes and no, and Adam Bien, who seems to be a Java EE expert, gives an unqualified yes.

My own experience with a simple scheduled bean suggests the answer is NO:

@Stateless
public class TimerTick implements TimerTickAbs, Runnable {
  @PersistenceContext private EntityManager entityManager;
  @Override
  public void run() {
    Query q = entityManager.createQuery("SELECT blah...");
  }
  @Override
  public Runnable runner() {
    return this;
  }
}

Abstract interface:

@Local
public interface TimerTickAbs {
  public Runnable runner();
}

Started with:

@Resource ManagedScheduledExecutorService managedExecutorService;
@EJB TimerTick myRunner;

public void startup()
{
    managedExecutorService.scheduleAtFixedRate(myRunner.runner(), 3, 40, TimeUnit.SECONDS);
}

If I print out the Thread.currentThread().getId(), even though I am still on the same thread between calls, I get:

SEVERE: java.lang.IllegalStateException: Attempting to execute an operation on a closed EntityManager

I know I can do code like @PersistenceUnit private EntityManagerFactory emf; and manage the EntityManager myself, but I'd like to take advantage of all the automatic transaction stuff that @PersistenceContext gives me.


Solution

  • No, an EntityManager is NOT thread safe. Adam Bien though is also correct. You are just not looking at the question correctly. The question he is answering isn't if an EntityManager is thread safe, he is stating that using container managed EntityManger in a stateless session bean is safe, which it is. He then explains the reasoning and wording of the spec that allows the container to work its magic - "each instance sees only a serialized sequence of method calls". That allows container injection to have different EntityManager contexts per method invocation, similar to how each invocation can be tied to their own transaction and isolated resources.

    Injection is really just injecting an EntityManager proxy that gives the container control over the lifecycle of the JPA EntityManagers underneath, allowing it to be tied to the thread and the transaction.

    So an EntityManager is NOT thread safe, but the container injected EntityManager proxies are required to be safe to use within stateless session beans.