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

时间:2010-03-08 07:01:12

标签: java jpa java-ee thread-safety ejb-3.0

我们有一些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?

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

编辑:更多信息。 ejb3.0 spec

  

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

而且,

  

4.3.2依赖注入   会话bean可以使用依赖注入   获取引用的机制   资源或其他对象   环境(见第16章,   “企业Bean环境”)。如果一个   会话bean利用依赖   注射,容器注入这些   bean实例之后的引用   创建,并在任何业务之前   在bean上调用方法   实例。如果依赖于   SessionContext被声明,或者如果是   bean类实现了可选   SessionBean接口(参见章节   4.3.5),此时也会注入SessionContext。如果依赖   注入失败,bean实例是   丢弃。在EJB 3.0 API下,   bean类可以获得   SessionContext接口通过   依赖注入而不必   实现SessionBean接口。   在这种情况下,资源注释   (或resource-env-ref部署   descriptor元素)用于表示   豆子的依赖性   SessionContext。见第16章,   “企业Bean环境”。

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:2)

我使用了类似的模式,但是助手是在@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节涵盖了一些主题。

答案 2 :(得分:0)

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

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

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