注入 EntityManager 与。实体管理器工厂

Posted

技术标签:

【中文标题】注入 EntityManager 与。实体管理器工厂【英文标题】:Injecting EntityManager Vs. EntityManagerFactory 【发布时间】:2010-11-21 13:24:12 【问题描述】:

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

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

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

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

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

【问题讨论】:

我进一步了解,当 Spring 注入 EntityManager 时,它是“容器管理的持久性”,并且 Spring“使”Entitymanagers 线程安全。某人 【参考方案1】:

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

【讨论】:

【参考方案2】:

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

话虽如此,你的问题中有些地方应该澄清一下。

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

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

注入 EMF 的论据是 这是一个很好的做法 有一个句柄总是好的 工厂。

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

【讨论】:

如果你不能改进他们的解释,你能解释一下吗?该文件中有很多内容,我并不完全明白它在哪里“拼写出来”。此外,最好有一个可以独立存在的答案,而不需要人们点击链接来查看您的完整答案。【参考方案3】:

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

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

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

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

【讨论】:

【参考方案4】:

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

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

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

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

跟进:

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

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

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

另一个跟进:

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

【讨论】:

以上是关于注入 EntityManager 与。实体管理器工厂的主要内容,如果未能解决你的问题,请参考以下文章

06 EntityManager和EntityTransaction

无法使用@PersistenceContext注入RESOURCE_LOCAL容器管理的EntityManager

Spring+JPA EntityManager 注入 service 和 dao

EntityManager 创建本机查询与持久化和注入

EntityManager方法简介

EntityManager 刷新