2009-08-21 96 views
64

一个很长的问题,请耐心等待。注入EntityManager VS. EntityManagerFactory

我们使用Spring + JPA作为Web应用程序。我的团队正在注入(基于泛型的DAO,由APPFUSE提供的线路,我们不使用JpaDaosupport出于某种原因)在注入EntityManager之后注入EntityManagerFactory。我们正在使用“应用程序管理持久性”。

反对注射EntityManagerFactory的论据是它太重,所以不需要,EntityManager做我们需要的。另外,由于Spring会为每个Web请求创建一个DAO的新实例(我怀疑这一点),所以不会有任何并发​​问题,因为两个线程共享相同的实例。

注射EFM的理由是,它是一个很好的实践,总是有很好的办法来处理工厂。

我不确定哪个是最好的方法,有人请赐教吗?

+2

我进一步理解,当Spring注入EntityManager时,它是“容器管理持久性”,并且Spring使得Entitymanagers线程安全。 SB – 2009-08-21 06:10:44

回答

49

注入EntityManagerFactory与EntityManager的优点和缺点都在Spring文档here中详细说明,我不确定是否可以改进。

说到这个问题,应该清除一些问题。

...春天将创造的 为每个Web请求一个DAO实例...

这是不正确的。如果你的DAO是一个Spring bean,那么它是一个单例,除非你通过bean定义中的scope属性来配置它。为每个请求实例化一个DAO将是疯狂的。

注入EMF的说法是, 它在一个很好的做法其所有 总是好的,有一个句柄 工厂。

这个说法并不是真的有水。一般的良好做法认为,应该向一个对象注入最低限度的合作者来完成其工作。

6

我发现在我们的DAO上设置@Repository Spring注解,并让Spring管理的EntityManager和@PersistenceContext注解注入是让所有的东西都能流利地工作的最方便的方法。您受益于共享EntityManager和异常转换的线程安全性。默认情况下,共享EntityManager将管理交易,如果您将多个来自经理的DAO组合在一起。最后你会发现你的DAO会变得贫血。

23

我放下了我最终收集的东西。从Spring参考一节“Implementing DAOs based on plain JPA”:

虽然EntityManagerFactory的实例是线程安全的,但EntityManager 情况并非如此。注入的JPA EntityManager的行为类似于从应用服务器的JNDI环境中获取的 EntityManager,如JPA规范所定义的 。它将所有调用委托给 当前事务型EntityManager(如果有);否则,它将每个操作的 降回到新创建的EntityManager,实际上使其线程安全的 使用成为可能。

这意味着按照JPA规范,EntityManager实例不是线程安全的,但是如果Spring处理它们,它们将变为线程安全的。

如果您使用Spring,最好注入EntityManagers而不是EntityManagerFactory。

9

我认为这已经被很好的涵盖,但只是为了强调几点。

  • 的DAO,如果由Spring注入,是 单默认。您必须将 明确将范围设置为原型 以每次创建一个新实例。

  • 通过 @PersistenceContext 注入实体管理器是线程安全的

这就是说,我确实在我的多线程应用程序中使用单例DAO时遇到了一些问题。 我最终使DAO成为一个实例bean,并解决了这个问题。 因此,虽然文档可能会说一件事,但您可能希望彻底测试您的应用程序。

后续:

我想我的问题的一部分是我使用

@PersistenceContext(unitName = "unit", 
    type = PersistenceContextType.EXTENDED) 

如果使用PersistenceContextType.EXTENDED,记住,你必须这样做,如果我理解正确的话,手动关闭交易。有关更多信息,请参阅this线程。

另一个后续:

使用实例化DAO是一个非常糟糕的主意。 DAO的每个实例都将拥有自己的持久性缓存,并且对其中一个缓存的更改不会被其他DAO Bean识别。对不起,不好的建议。