是否可以将注入的EntityManagers传递给EJB bean的帮助程序类并使用它?

我们有一些JavaEE5无状态EJB bean,它将注入的EntityManager传递给它的帮助器。

这样安全吗? 到目前为止它运行良好,但我发现了一些Oracle文档,声明它的EntityManager实现是线程安全的。 现在我想知道我们之前没有问题的原因是因为我们使用的实现恰好是线程安全的(我们使用Oracle)。

@Stateless class SomeBean { @PersistenceContext private EntityManager em; private SomeHelper helper; @PostConstruct public void init(){ helper = new SomeHelper(em); } @Override public void business(){ helper.doSomethingWithEm(); } } 

实际上它是有道理的。如果EntityManager是线程不安全的,那么容器就必须这样做

 inercept business() this.em = newEntityManager(); business(); 

它不会传播到它的帮助器类。

如果是这样,在这种情况下最好的做法是什么? 传递EntityManagerFactory而不是EntityManager?

编辑: 这个问题非常有趣,所以如果你对这个问题感兴趣,你可能也想看一下这个问题:

编辑:更多信息。 ejb3.0规范

4.7.11非重入实例容器必须确保任何时候只有一个线程可以执行实例。 如果客户端请求在实例执行另一个请求时到达实例,则容器可能会将javax.ejb.ConcurrentAccessException抛出到第二个客户端[24]。 如果使用EJB 2.1客户端视图,则容器可能会在客户端是远程客户端时将java.rmi.RemoteException抛出到第二个请求,如果客户端是本地客户端,则抛出javax.ejb.EJBException。[25] 请注意,会话对象仅支持单个客户端。 因此,如果两个客户端尝试调用同一会话对象,则会出现应用程序错误。 此规则的一个含义是应用程序无法对会话Bean实例进行环回调用。

和,

4.3.2dependency injection会话bean可以使用dependency injection机制来获取对其环境中的资源或其他对象的引用(请参阅第16章“Enterprise Bean Environment”)。 如果会话bean使用dependency injection,则容器会在创建bean实例之后,以及在bean实例上调用任何业务方法之前注入这些引用。 如果声明了对SessionContext的依赖,或者bean类实现了可选的SessionBean接口(参见第4.3.5节),则此时也会注入SessionContext。 如果依赖项注入失败,则丢弃bean实例。 在EJB 3.0 API下,bean类可以通过dependency injection获取SessionContext接口,而无需实现SessionBean接口。 在这种情况下,Resource annotation(或resource-env-ref部署描述符元素)用于表示bean对SessionContext的依赖性。 请参见第16章“Enterprise Bean环境”。

我使用了类似的模式,但是助手是在@PostConstruct中创建的,注入的实体管理器在构造函数中作为参数传递。 每个EJB实例都有自己的帮助器,然后保证线程安全。

我还有一个变体是没有注入实体管理器(因为EJB没有完全使用它),所以帮助者必须使用InitialContext查找它。 在这种情况下,仍然必须使用@PersistenceContext在父EJB中“导入”持久性上下文:

 @Stateless @PersistenceContext(name="OrderEM") public class MySessionBean implements MyInterface { @Resource SessionContext ctx; public void doSomething() { EntityManager em = (EntityManager)ctx.lookup("OrderEM"); ... } } 

但它实际上更容易注入(即使EJB不使用它)而不是查找它,特别是对于可测试性。

但回到你的主要问题,我认为注入或查找的实体管理器是一个包装器,它转发到绑定到事务的底层活动实体管理器。

希望能帮助到你。

编辑

规范中的第3.3节和第5.6节涵盖了一些主题。

我一直在使用辅助方法并在那里传递EntityManager ,这完全没问题。

所以我建议在需要时将它传递给方法,或者让helper成为bean本身,注入它(使用@EJB )并在那里注入EntityManager

好吧,就个人而言,我不想将实体管理器传递给我的构造函数或方法中的所有POJO。 特别是对于POJO数量很大的非平凡程序。

我会尝试创建处理EntityManager返回的实体的POJO / HelperClasses,而不是直接使用entitymanager。

如果不可能,我想我会创建一个新的EJB Bean。