用 CDI 做这样的事情安全吗?
@Named
@ApplicationScoped
public class DAO {
@PersistenceContext
private EntityManager entityManager;
}
我了解
EntityManager
本身不是线程安全的,因此不应在像
@ApplicationScoped
这样的共享全局上下文中使用。 .但是,由于注入(inject)的对象带有
@PersistenceContext
实际上是底层
EntityManager
周围的线程感知包装器,这样可以吗?
我已经看过有关该主题的其他帖子,但无法为这个特定案例找出权威答案。例如:
Java CDI @PersistenceContext and thread safety
看起来与
@Stateless
一起使用是安全的,例如 - 但我不确定这是否是因为
@Stateless
的方式有效,或者因为
@PersistenceContext
的内在原因本身。
编辑
我困惑的根源是
@PersistenceContext
注入(inject)
EntityManager
wrapper 似乎知道当前线程,以便确定是否已经有正在进行的事务。所以也许我把线程意识和线程安全混淆了,它们是两个不同的东西。
请您参考如下方法:
我很确定在这种情况下 CDI 不会为实体管理器创建上下文代理。毕竟,它会在什么范围内?您可能想要类似于假设 @ThreadScoped
的东西。或只是 @RequestScoped
, 但是 @PersistenceContext
不是 CDI 注释,CDI 不会修改其语义。
所以这里发生的是 Java EE 6 平台“托管 bean”注入(inject),它类似于在 Servlet 中注入(inject)实体管理器。这两种情况都为您提供了一个不能直接使用线程安全的实例。
It looks like it's safe to use with @Stateless, for instance - but I'm not sure if that's because of the way @Stateless works, or because of something intrinsic to @PersistenceContext itself.
是因为方式
@Stateless
作品。对无状态 bean 上的方法的每个请求(调用)都由容器路由到唯一的实例。容器保证没有两个线程在同一个 bean 中处于事件状态。
使用 CDI,您可以通过将实体管理器封装在请求范围的 bean 中并将其注入(inject)到应用程序范围的 bean 中来获得每个请求的类似效果:
import javax.enterprise.context.RequestScoped;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@RequestScoped
public class EntityManagerProvider {
@PersistenceContext
private EntityManager entityManager;
public EntityManager getEntityManager() {
return entityManager;
}
}
将其注入(inject)到您之前注入(inject)实体管理器的 bean 中:
@Named
@ApplicationScoped
public class DAO {
@Inject
private EntityManagerProvider entityManagerProvider;
}
这将为您提供每个请求的唯一实体管理器。您也可以轻松地将其转换为生产者方法,因此您不必调用
getEntityManager()
在注入(inject)的提供者上。