JPA实体管理器应该关闭吗?
我有下面的方法。
public Profile readUser(String email){
EntityManager em = EMF.get().createEntityManager();
return em.find(Profile.class, email);
}
实体管理器的上述用法可以吗?还是有必要关闭它们?任何建议请。
我有下面的方法。
public Profile readUser(String email){
EntityManager em = EMF.get().createEntityManager();
return em.find(Profile.class, email);
}
实体管理器的上述用法可以吗?还是有必要关闭它们?任何建议请。
我想答案是:视情况而定。
实体管理器是访问实体所在上下文的关键。如果您的应用程序是 JSE 应用程序,则必须考虑上下文的预期寿命是多少。
让我们考虑一下,您将为每个用户的请求创建一个实体管理器。因此,当您处理给定的请求时,您将保持实体经理处于打开状态,并在完成该请求时将其关闭。
在 JSE 应用程序中,您可能已经考虑过要在应用程序的整个生命周期内保持实体管理器处于打开状态(假设您没有处理大量数据),然后在应用程序关闭时将其关闭。
底线,何时打开它以及何时关闭完全取决于您的策略和设计。当您不再需要其上下文中的实体时,请将其关闭。
在您的示例中,这并不明显,但是由于您正在该方法中创建EM,因此您应该在返回之前将其关闭,否则您将无法再访问它(除非您将其保存在某个注册表中,这在代码中并不明显)。
如果不关闭它,即使使用完实体,您的实体也将保持附件状态。即使您无法再访问您的EM,您的上下文也将保持活动状态。
JPA 规范包含更多详细信息。在 7.7 节“应用程序管理的持久性上下文”中,它说:
使用应用程序管理的实体管理器时,应用程序直接与持久性提供程序的实体管理器工厂交互,以管理实体管理器生命周期并获取和销毁持久性上下文。
所有这些应用程序管理的持久性上下文都扩展了范围,并且可以跨多个事务。
方法和 and 方法用于管理应用程序管理的实体管理器的生命周期及其关联的持久性上下文。
EntityManagerFactory.createEntityManager
EntityManager
close
isOpen
扩展的持久性上下文从使用创建实体管理器的点开始存在,直到实体管理器通过 关闭。
EntityManagerFactory.createEntityManager
EntityManager.close
从应用程序管理的实体管理器获取的扩展持久性上下文是独立的持久性上下文,它不会随事务一起传播。
[...]该方法关闭实体管理器以释放其持久性上下文和其他资源。调用 close 后,应用程序不得在实例上调用除 and 以外的任何其他方法,否则将引发 。如果在事务处于活动状态时调用 close 方法,则在事务完成之前,持久性上下文将保持托管状态。
EntityManager.close
EntityManager
getTransaction
isOpen
IllegalStateException
该方法指示实体管理器是否处于打开状态。该方法返回 true,直到实体管理器已关闭。要真正理解它是如何工作的,了解实体经理和上下文之间的关系至关重要。
EntityManager.isOpen
isOpen
因此,如您所见,实体管理器是您访问实体的公共接口,但是,您的实体驻留在附加到实体管理器的上下文中。了解不同类型的上下文的生命周期将回答您的问题。
持久性上下文可以是不同的类型。在 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事务,对吧?因此,您使用资源本地事务,并负责手动提交或回滚更改。
对于此类应用程序,当您实例化实体管理器时,上下文会自动附加到它。
根据您的应用程序,您可以决定创建一个全局实体管理器,其生命周期附加到应用程序本身的生命周期。这是应用程序整个生命周期的单个实体管理器。在这种情况下,将使用实体管理器创建和销毁您的上下文。
或者,您可以为每个与应用程序用户的对话(即事务)创建一个实体管理器。在这种情况下,范围由您决定,但您的上下文仍将通过实体管理器创建和销毁。