Thread-safety when injecting JPA EntityManager
Injecting EJB 3 stateful beans into servlet instance fields is not thread-safe. Along the same line, injecting EntityManager with @PersistenceContext into servlet instance variables is not thread-safe, either. EntityManager is just not designed to be thread-safe.For example, the following code snippet of a servlet class is incorrect:
1 2 3 4 5 6 7 | public class EMTestServlet extends HttpServlet { //This field injection is not thread-safe. //FIXME @PersistenceContext private EntityManager em; ... } |
One way to fix this is to inject EntityManagerFactory instead. EntityManagerFactory is guaranteed to be thread-safe. For example:
1 2 3 4 5 6 7 8 9 10 11 12 | public class EMTestServlet extends HttpServlet { //This field injection is thread-safe @PersistenceUnit private EntityManagerFactory emf; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { EntityManager em = emf.createEntityManager(); //work with em } } |
Continuing container-managed EntityManager vs application-managed EntityManager.
There are important differences between the injected EntityManager, and the EntityManager created from an injected EntityManagerFactory. Basically, injected EntityManager is container-managed, meaning all of its lifecycle is controlled by the container (web container or EJB container). Application code cannot close it, or otherwise interfere with its life.
In addition, for a container-managed EntityManager, its associated PersistenceContext is automatically propagated along with the underlying JTA, from servlet A to servlet B, from servlet to EJB, from EJB a to EJB B, and so on. As such, EntityManager of the same configuration injected into various classes can share the same PersistenceContext in a call stack.
On the other hand, EntityManager created from EntityManagerFactory is application-managed EntityManager. Application code is responsible for managing its whole lifecycle. And there is no PersistenceContext propagation for application-managed EntityManager.
Are all EntityManager's obtained from EntityManagerFactory application-managed EntityManager? Yes.
Is it possible to get a container-managed EntityManager from EntityManagerFactory? No.
You may have read about the method EntityManagerFactory.getEntityManager(), which returns a container-managed EntityManager. This method was considered and included in the early draft version of Java Persistence API, but was eventually removed from its final release.
posted on 2013-02-04 10:49 gembin 閱讀(818) 評論(0) 編輯 收藏 所屬分類: JavaEE