保持 JPA EntityManager 打开?

Posted

技术标签:

【中文标题】保持 JPA EntityManager 打开?【英文标题】:Keeping JPA EntityManager open? 【发布时间】:2010-08-03 02:18:37 【问题描述】:

我正在学习 JPA,示例中的一般模式似乎如下:

EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
// ....
em.getTransaction().commit();
em.close();

现在我想知道为什么我们要不断地创建和关闭 EntityManager,而不是保持它打开并开始新的事务?保持打开和一直关闭的好处和成本是什么?

【问题讨论】:

【参考方案1】:

想到两个特定于 JPA 的原因:

    JPA 规范不保证 EntityManager 是线程安全的。因此,便携式 JPA 应用程序一次最多只能在一个线程中使用 EM。创建方法本地 EM 并在其超出范围之前将其关闭的习惯用法鼓励对 EM 引用进行堆栈限制。

    使用“扩展”持久性上下文生命周期的 EM 在其整个存在期间维护一个持久性上下文。这意味着实体在commit() 上停止自动分离。相反,它们必须手动分离,否则 EM 仍然负责跟踪它们。

这个问题实际上是旧的“何时池化对象”问题的 JPA 特定版本。这很难,但答案可能是“很少”。

Java 并发专家 Brian Goetz 的 old developerWorks post 阐述了这一点。要点:池对于昂贵的对象(例如数据库连接)非常有意义。但是对于像 EntityManager 这样的短期、小型和快速初始化的对象,池化或其他形式的长期引用保留是很难卖的。

但是,这是一个普遍的问题,所以肯定会有例外。也许应用程序是简单的或单线程的。那么这些关于线程安全的担忧就变得没有意义了。

【讨论】:

【参考方案2】:

保持实体管理器处于打开状态可防止其将连接返回到连接池。

这可能会导致一些问题,尤其是在 Web 应用程序中,例如当池已满且达到最大连接大小时,其他用户无法获得数据库连接,从而阻止该用户访问数据库。

在这种情况下,最好有短暂的实体管理器,例如在请求开始时打开实体管理器并在请求结束时关闭它(可以使用侦听器/拦截器来完成..)。然后实体分离,如果您想再次使用它们,您必须重新附加它们(使用实体管理器的合并操作)。

【讨论】:

以上是关于保持 JPA EntityManager 打开?的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot - Mysql Driver - JPA - 在服务器运行发布请求很长时间后显示无法打开 JPA EntityManager 进行事务处理

无法打开 JPA EntityManager 进行事务处理;嵌套异常是 org.hibernate.exception.SQLGrammarException:无法获取 JDBC 连接

JPA学习笔记(11)——使用二级缓存

怎样用JPA的EntityManager执行原生sql返回ResultSet-CSDN论坛

即使抛出错误,JPA EntityManager persist() 也会导致对象看起来分离

何时将 EntityManager.find() 与 EntityManager.getReference() 与 JPA 一起使用