JPA实体经理应该关闭吗?

时间:2012-05-26 01:27:49

标签: java jpa

我有以下方法。

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

实体经理的上述用法是否可以?或者有必要关闭他们吗?请提出任何建议。

1 个答案:

答案 0 :(得分:115)

我想答案是:它取决于

您的实体经理是获取实体所在环境的关键。如果您的应用程序是JSE应用程序,则必须考虑上下文的​​预期寿命。

让我们考虑您将根据用户的请求创建实体管理器。因此,当您参加某个请求时,您将保持您的实体经理处于打开状态,当您完成它时,您将其关闭。

在JSE应用程序中,您可能认为您希望让实体经理在应用程序的整个生命周期内打开(假设您没有处理大量数据),然后在应用程序中关闭它关闭了。

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

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

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

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

  

使用应用程序管理的实体管理器时,应用程序   直接与持久性提供程序的实体管理器交互   工厂管理实体经理的生命周期并获得和   破坏持久性语境。

     

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

     

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

     

扩展持久化上下文存在于   已使用创建实体管理器   EntityManagerFactory.createEntityManager直到实体经理为止   通过EntityManager.close关闭。

     

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

     

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

     

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

因此,您可以看到实体管理器是您通过其访问实体的公共接口,但是,您的实体驻留在上下文中,并附加到您的实体管理器。了解不同类型背景的生命周期将回答您的问题。

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

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

<强>事务范围

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

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

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

扩展持久性上下文

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

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

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

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

<强>应用程序管理

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

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

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

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

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