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