在多个类线程安全中,如下所示是EntityManager @Inject [ed]吗?
@PersistenceContext(unitName="blah")
private EntityManager em;
尽管EntityManager实现本身不是线程安全的,但Java EE容器注入了一个代理,该代理将所有方法调用委派给绑定了事务[
EntityManager
的新实例,则以下操作将无效:@Stateless
public class Repository1 {
@EJB
private Repository2 rep2;
@PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION)
private EntityManager em;
@TransactionAttribute
public void doSomething() {
// Do something with em
rep2.doSomethingAgainInTheSameTransaction();
}
}
@Stateless
public class Repository2 {
@PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION)
private EntityManager em;
@TransactionAttribute
public void doSomethingAgainInTheSameTransaction() {
// Do something with em
}
}
。实际上,它们共享同一个代理EntityManager,该代理将调用委派给相同的持久性上下文。因此您可以在单例bean中合法使用doSomething-> doSomethingAgainInTheSameTransaction调用发生在单个事务中,因此Bean必须共享相同的EntityManager
EntityManager
,如下所示:@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class Repository {
@PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION)
private EntityManager em;
}
另一个证明是,在[[EntityManagerjavadoc中没有提及线程安全性。因此,当您留在
Java EE容器中时,您无需关心对EntityManager的并发访问。
EntityManager
只是本机JPA实现的包装,例如Hibernate中的会话,这反过来又是jdbc连接的包装器。就是说EntityManager
不能是线程安全的,因为它表示一个数据库连接/事务。那么为什么它在Spring中起作用?因为它将目标EntityManager
包装在代理中,所以原则上使用ThreadLocal
保留每个线程的本地引用。这是必需的,因为Spring应用程序建立在单例之上,而EJB使用对象池。
EntityManager
决不能同时使用。话虽如此,注入EntityManager
是安全的
但是但是将EntityManager
注入到servlet和单例bean中并不安全,因为可能有多个线程可以同时访问它们,并弄乱了相同的JDBC连接。
JSR-220(EJB 3.0)。在
5.2获取EntityManager部分中,您可以找到:
[实体管理器不得同时在多个实体之间共享执行线程。实体管理器只能在单线程方式。就是这样。您可能会在这里停止阅读,并且除非正确同步,否则不要在单例bean中使用。EntityManager
但是我相信规范中存在混淆。实际上有两种不同的EntityManager
实现。第一个是提供程序实现(例如Hibernate),它不一定是线程安全的。另一方面,有一个EntityManager
的容器实现。根据以上所述,也不应该认为它是线程安全的。但是容器的实现充当代理,并将所有调用委派给真实提供者的EntityManager。因此在5.9容器与持久性之间的运行时合同提供者
:用于管理事务范围的持久性上下文,如果没有与JTA事务关联的EntityManager:容器通过调用创建新的实体管理器首次调用EntityManagerFactory.createEntityManager时发生具有Persistence- ContextType.TRANSACTION的实体管理器在JTA中执行的业务方法范围内交易。
这意味着依次启动的每个事务都有一个不同的实例。根据EntityManager
5.3:,创建EntityManager的代码是安全的EntityManagerFactory接口的方法是线程安全的。
但是,如果有与JTA事务关联的怎么办?根据规范,绑定与当前JTA事务关联的EntityManager
EntityManager的代码可能不是线程安全的。 但是我真的想不起来一个应用服务器实现,它可以正确地将EntityManager
注入到无状态Bean中,并且不能在单例中正确运行。所以我的结论是:
如果要严格遵循