注入EntityManager Vs. EntityManagerFactory的

时间:2009-08-21 04:28:04

标签: java spring jpa entitymanager

一个很长的问题,请耐心等待。

我们正在将Spring + JPA用于Web应用程序。我的团队正在讨论在EntityManagerFactory中注入GenericDAO(基于泛型的DAO,APPFUSE提供的内容,我们出于某种原因不使用JpaDaosupport)而不是注入EntityManager 1}}。我们正在使用“应用程序管理持久性”。

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

注入EFM的理由是,对于工厂来说,这是一个很好的做法。

我不确定哪种方法最好,有人可以赐教吗?

4 个答案:

答案 0 :(得分:51)

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

说,你的问题中有一些问题需要澄清。

  

... Spring会创建一个新的实例   每个网络请求的DAO ......

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

  

注入EMF的论点是   它是一个很好的做法   总是很好的掌握一个   工厂。

这个论点并不真正有用。一般的良好实践表明,应该向一个对象注入完成其工作所需的最少合作者。

答案 1 :(得分:24)

我正在放下我最终收集到的东西。从Spring Reference中的“Implementing DAOs based on plain JPA”部分:

  

虽然EntityManagerFactory实例是线程安全的,但EntityManager   实例不是。注入的JPA EntityManager的行为类似于   EntityManager从应用程序服务器的JNDI环境中获取,   由JPA规范定义。它将所有呼叫委托给   当前事务性EntityManager,如果有的话;否则,它会回落   到每个操作新创建的EntityManager,实际上是它的   用法线程安全。

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

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

答案 2 :(得分:9)

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

  • DAO,如果由Spring注入,是一个 单身默认。你必须 显式地将范围设置为原型 每次都要创建一个新实例。

  • 注入的实体经理 @PersistenceContext 是线程安全的

话虽如此,我的多线程应用程序中的单例DAO确实存在一些问题。 我最终把DAO变成了一个实例bean,解决了这个问题。所以虽然文档可能会说一件事,但你可能想彻底测试你的应用程序。

跟进:

我认为我的部分问题是我正在使用

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

如果您使用PersistenceContextType.EXTENDED,请记住,如果我理解正确,您必须手动关闭事务。有关详细信息,请参阅this主题。

另一项跟进:

使用实例化DAO是一个非常糟糕的主意。 DAO的每个实例都有自己的持久性缓存,其他DAO bean无法识别对一个缓存的更改。抱歉,这是一个糟糕的建议。

答案 3 :(得分:6)

我发现在我们的DAO上设置@Repository Spring注释并使用Spring管理的EntityManager并通过@PersistenceContext注释注入是使一切工作流畅的最方便的方法。您可以从共享EntityManager的线程安全性和异常转换中受益。默认情况下,如果您将来自管理器的多个DAO组合在一起,则共享的EntityManager将管理事务。最后你会发现你的DAO会变得贫血。