88

我有下面的方法。

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

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

4

1 回答 1

141

我想答案是:这取决于.

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

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

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

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

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

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

JPA 规范包含更多细节。在第7.7 节应用程序管理的持久性上下文中它说:

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

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

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

扩展的持久性上下文从创建实体管理器的那一刻开始一直存在, EntityManagerFactory.createEntityManager直到实体管理器通过EntityManager.close.

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

[...] 该EntityManager.close方法关闭实体管理器以释放其持久性上下文和其他资源。调用 close 后,应用程序不得在 EntityManager实例上调用除getTransactionand之外的任何其他方法isOpen,否则IllegalStateException将抛出 。如果在事务处于活动状态时调用 close 方法,则持久性上下文将保持受管理状态,直到事务完成。

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

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

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

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

事务范围

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

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

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

扩展持久性上下文

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

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

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

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

应用程序管理

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

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

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

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

Or, you could create an entity manager per conversation (i.e. transaction) with your application user. The scope, in this case, is determined by you, but still, your context will be created and destroyed with your entity manager.

于 2012-05-26T01:51:45.717 回答