【问题标题】:Should JPA Entity Manager be closed?JPA Entity Manager 应该关闭吗?
【发布时间】:2023-03-14 16:54:01
【问题描述】:

我有下面的方法。

public Profile readUser(String email){
    EntityManager em = EMF.get().createEntityManager();
    return em.find(Profile.class, email);
}

上面实体管理器的用法可以吗?或者有必要关闭它们吗?请有任何建议。

【问题讨论】:

标签: java jpa


【解决方案1】:

我想答案是:视情况而定

您的实体管理器是访问实体所在上下文的关键。如果您的应用程序是 JSE 应用程序,则必须考虑上下文的​​预期寿命。

假设您将根据用户的请求创建一个实体管理器。因此,当您处理给定的请求时,您将保持您的实体管理器处于打开状态,当您完成它时,您将其关闭。

在 JSE 应用程序中,您可能考虑过希望实体管理器在应用程序的整个生命周期中保持打开状态(假设您不处理大量数据),然后在应用程序关闭时关闭它.

底线,何时打开和何时关闭完全取决于您的策略和设计。当您不再需要其上下文中的实体时,您将其关闭。

在您的示例中,这并不明显,但是由于您在方法中创建了 EM,因此您应该在返回之前将其关闭,否则您将无法再次访问它(除非您将其保留在一些注册表,这在代码中并不明显)。

如果您不关闭它,您的实体将保持为附加状态,即使在您使用完它们之后也是如此。即使您无法再访问您的 EM,您的上下文也将保持活动状态。

JPA Specification 包含更多详细信息。在 7.7 应用程序管理的持久性上下文部分中它说:

当使用应用程序管理的实体管理器时,应用程序 直接与持久化提供者的实体管理器交互 工厂来管理实体管理器的生命周期并获取和 销毁持久化上下文。

所有此类应用程序管理的持久性上下文都在 范围,并且可以跨越多个事务。

EntityManagerFactory.createEntityManager 方法和 EntityManager closeisOpen 方法用于管理 应用程序管理的实体管理器及其关联的生命周期 持久化上下文。

扩展的持久性上下文存在于 实体管理器已使用 EntityManagerFactory.createEntityManager 直到实体管理器 通过EntityManager.close 关闭。

从应用程序管理的扩展持久性上下文 实体管理器是一个独立的持久性上下文,它不是 与交易一起传播。

[...] EntityManager.close 方法关闭实体管理器以 释放其持久性上下文和其他资源。打电话后 关闭,应用程序不得在 EntityManager 实例,getTransactionisOpen 除外,或 IllegalStateException 将被抛出。如果关闭方法是 当事务处于活动状态时调用,持久性上下文保持不变 管理直到事务完成。

EntityManager.isOpen方法表示实体管理器是否 开了。 isOpen 方法返回 true,直到实体管理器 被关闭。 要真正了解其工作原理,了解实体管理器与上下文之间的关系至关重要。

因此,正如您所见,实体管理器是您访问实体的公共接口,但是,您的实体驻留在一个上下文中,附加到您的实体管理器。了解不同类型上下文的生命周期将回答您的问题。

持久性上下文可以是不同的类型。在 Java EE 应用程序中,您可以拥有事务范围的持久性上下文扩展的持久性上下文。在 JSE 应用程序中,上下文的性质由开发人员控制

当您向实体管理器请求实体时,它会在其附加的上下文中查找该实体,如果在那里找到该实体,则返回该实体,否则,它会从数据库中检索该实体。在上下文中对该实体的后续调用将返回相同的实体。

事务范围

在使用事务范围持久性上下文的 Java EE 应用程序中,当您第一次访问实体管理器时,它会检查当前 JTA 事务是否附加了上下文,如果尚不存在上下文,则会创建一个新上下文并创建实体manager 与此上下文相关联。然后从数据库中读取实体(如果存在,则从缓存中读取)并将其放入上下文中。当您的事务结束(提交或回滚)时,上下文变得无效并且其中的任何实体都变得分离。这是无状态会话 bean 的经典场景。

@PersistenceContext(unitName="EmplService")
EntityManager em;

这也意味着,根据您设计交易的方式,您最终可能会得到多个上下文。

扩展持久性上下文

在具有状态会话 bean 的 Java EE 应用程序中,您可能希望上下文能够在多个 bean 调用中存活,因为您不喜欢在 bean 被标记为删除之前提交,对吗?在这些情况下,您需要使用扩展的持久性上下文。在这种情况下,持久化上下文是在第一次需要时创建的,但在您将有状态 bean 标记为要删除之前,它不会变得无效。

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

这意味着,无论在后续调用有状态会话 bean 方法时注入此 bean 的实体管理器实例如何,您都可以确保您将始终访问相同的上下文,因此,即使后续调用也会返回相同的实例,因为它是相同的上下文。

此外,在将 bean 标记为删除或您手动刷新它们之前,您的更改不会被刷新。

应用程序管理

您始终可以手动实例化您的实体管理器工厂和实体管理器。这是您通常在 JSE 应用程序中所做的,对吗?

对于这类应用程序,您通常没有容器来处理 JTA 事务,对吗?因此,您使用资源本地事务并负责手动提交或回滚更改。

对于这种应用程序,当您实例化您的实体管理器时,上下文会自动附加到它。

根据您的应用程序,您可以决定创建一个全局实体管理器,其生命周期与应用程序本身的生命周期相关联。这是应用程序整个生命周期的单个实体管理器。在这种情况下,您的上下文将由您的实体管理器创建和销毁。

或者,您可以为每个与应用程序用户的对话(即事务)创建一个实体管理器。在这种情况下,范围由您决定,但您的上下文仍将由您的实体管理器创建和销毁。

【讨论】:

  • 很好的答案,但我需要知道:在会话期间多次打开和关闭 EntityManager 有性能高成本吗?只实例化和关闭一次,或者在每个数据库 crud 操作中实例化/使用/关闭它,这是最好的方法? “这取决于”好的,但必须更适合大多数用例..
  • @tomurlh 就我而言,创建EntityManager 的成本必须可以忽略不计。从我的角度来看,EntityManager 只是处理当前事务的unit of work 的抽象。我相信每次交易创建和销毁一个是完全可以的。现在,它确实有其他含义,因为 EntityManager 服务器作为您的实体的事务缓存,因此具有明确定义的事务范围并正确处理实体可能会利用此缓存。
  • EntityManager.close 方法关闭实体管理器以释放其持久化上下文什么是持久化上下文?
  • 这也意味着,根据您设计交易的方式,您最终可能会得到多个上下文。您能解释一下如何吗?
猜你喜欢
  • 1970-01-01
  • 2019-07-14
  • 2019-08-16
  • 1970-01-01
  • 2015-06-27
  • 2013-08-05
  • 2011-09-01
  • 2023-01-06
  • 2014-09-16
相关资源
最近更新 更多