71

一个很长的问题,请多多包涵。

我们将 Spring+JPA 用于 Web 应用程序。我的团队正在讨论是否注入EntityManagerFactoryGenericDAO基于泛型的 DAO,APPFUSE 提供的线路,我们JpaDaosupport出于某种原因不使用)而不是注入EntityManager. 我们正在使用“应用程序管理的持久性”。

反对注入 a 的论点EntityManagerFactory是它太重了,所以不是必需的,它可以满足EntityManager我们的需要。此外,由于 Spring 将为每个 Web 请求创建一个 DAO 的新实例(我对此表示怀疑),因此不会出现任何并发问题,因为在同一个EntityManager实例中由两个线程共享。

注入 EFM 的论点是,它是一个很好的实践,总之,拥有一个工厂的句柄总是好的。

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

4

4 回答 4

51

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

话虽如此,您的问题中有一些问题应该澄清。

...Spring 将为每个 Web 请求创建一个新的 DAO 实例...

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

注入 EMF 的论点是,它是一个很好的实践,总之,拥有一个工厂的句柄总是好的。

这个论点确实站不住脚。一般的良好实践表明,一个对象应该被注入完成其工作所需的最少协作者。

于 2009-08-21T07:10:57.023 回答
28

我正在放下我终于收集到的东西。从Spring Reference 中的“基于普通 JPA 实现 DAO ”部分:

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

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

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

于 2009-08-21T11:39:57.057 回答
9

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

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

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

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

跟进:

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

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

如果您使用 PersistenceContextType.EXTENDED,请记住,如果我理解正确,您必须手动关闭事务。有关更多信息,请参阅线程。

另一个后续:

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

于 2009-08-21T11:43:37.003 回答
7

我发现在我们的 DAO 上设置 @Repository Spring 注释并让 EntityManager 由 Spring 管理并由 @PersistenceContext 注释注入是让一切顺利运行的最方便的方法。您将从共享 EntityManager 的线程安全和异常转换中受益。默认情况下,如果您从一个管理器中组合多个 DAO,共享的 EntityManager 将管理事务。最后你会发现你的 DAO 会变得乏力。

于 2009-08-21T06:44:24.593 回答