保持 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的EntityManager执行原生sql返回ResultSet-CSDN论坛
即使抛出错误,JPA EntityManager persist() 也会导致对象看起来分离
何时将 EntityManager.find() 与 EntityManager.getReference() 与 JPA 一起使用