Thread-safety when injecting JPA EntityManager

3724 ワード

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.