JPA实体经理应该closures吗?
我有下面的方法。
public Profile readUser(String email){ EntityManager em = EMF.get().createEntityManager(); return em.find(Profile.class, email); }
实体经理的上述用法可以吗? 或者有必要closures它?任何build议请。
我想答案是: 这取决于 。
您的实体经理是访问实体所在环境的关键。 如果您的应用程序是JSE应用程序,则必须考虑您的上下文的预期寿命。
让我们考虑一下你将为每个用户的请求创build一个实体pipe理器。 所以,当你参加一个特定的请求时,你会保持你的实体经理开放,当你完成它,你closures它。
在JSE应用程序中,您可能已经考虑过要让实体pipe理器打开应用程序的整个生命周期(假设您没有处理大量数据),那么在应用程序closures时closures它。
底线,当你打开它,当你closures完全取决于你的策略和你的devise。 当你不再需要上下文中的实体时,可以closures它。
在你的例子中,这是不明显的,但是因为你在方法中创buildEM,所以在返回之前应该closures它,否则你将不再能够访问它(除非你把它保存在一些registry中,在代码中不明显)。
如果你不closures它,即使在你使用它们之后,你的实体也会被保留下来。 即使您不能再访问您的EM,您的上下文仍将保持活动状态。
JPA规范包含更多细节。 在第7.7节“ 应用程序pipe理的持久性上下文”中说:
当使用应用程序pipe理的实体pipe理器时,应用程序直接与持久性提供者的实体pipe理器工厂交互以pipe理实体pipe理器生命周期并获取和销毁持久性上下文。
所有这样的应用程序pipe理的持久性上下文都在范围内扩展,并且可以跨越多个事务。
EntityManagerFactory.createEntityManager
方法和EntityManager
close
和isOpen
方法用于pipe理应用程序pipe理的实体pipe理器及其关联的持久性上下文的生命周期。扩展持久化上下文存在于实体pipe理器已经使用
EntityManagerFactory.createEntityManager
创build的点上,直到通过EntityManagerFactory.createEntityManager
closures实体pipe理器为止。从应用程序pipe理的实体pipe理器获得的扩展持久性上下文是独立的持久性上下文,它不与事务一起传播。
EntityManager.close
方法closures实体pipe理器以释放其持久性上下文和其他资源。 调用close之后,除了getTransaction
和isOpen
之外,应用程序不能调用EntityManager
实例的其他方法,否则将引发IllegalStateException
。 如果在事务处于活动状态时调用close方法,则持续上下文将保持pipe理状态,直到事务完成。
EntityManager.isOpen
方法指示实体pipe理器是否处于打开状态。isOpen
方法返回true,直到实体pipe理器closures。 要真正理解这是如何工作的,理解实体pipe理器和上下文之间的关系是至关重要的。
所以,正如你所看到的,实体pipe理器是你通过其访问实体的公共接口,然而,你的实体驻留在一个与你的实体pipe理器相连的上下文中。 了解不同types的上下文的生命周期将回答你的问题。
持久性上下文可以是不同的types。 在Java EE应用程序中,您可以具有事务范围的持久性上下文或扩展持久性上下文 。 在JSE应用程序中,上下文的性质由开发人员来控制 。
当你向你的实体pipe理器请求一个实体时,它会在其附加的上下文中查找该实体,如果它在那里find该实体,则返回该实体,否则从数据库中检索该实体。 随后在上下文中调用此实体将返回相同的实体。
事务范围
在使用事务范围持久化上下文的Java EE应用程序中,当您第一次访问实体pipe理器时,它会检查当前JTA事务是否附加了上下文,如果尚未存在上下文,则创build新的上下文并且实体pipe理器是链接到这个上下文。 然后从数据库中读取实体(如果存在,则从caching中读取)并将其放入上下文中。 当事务结束(提交或回滚)时,上下文变为无效,并且其中的任何实体都被分离。 这是无状态会话bean的经典场景。
@PersistenceContext(unitName="EmplService") EntityManager em;
这也意味着,根据您devise交易的方式,最终可能会有多个上下文。
扩展持久性上下文
在具有有状态会话bean的Java EE应用程序中,您可能希望上下文能够在多个bean调用中生存下来,因为在bean被标记为删除之前,您不想提交它,对吗? 在这些情况下,您需要使用扩展的持久性上下文。 在这种情况下,持久化上下文是在第一次需要的时候被创build的,但是直到你将有状态的bean标记为删除,它才会变得无效。
@PersistenceContext(unitName="EmplService", type=PersistenceContextType.EXTENDED)
这意味着,无论在随后的statefull会话bean方法调用中注入此bean的实体pipe理器的实例如何,您都可以确保始终访问相同的上下文,因此即使后续调用也会返回相同的实例,因为它是相同的上下文。
此外,只有当bean被标记为删除或者手动刷新它们时,您的更改才会被刷新。
应用程序托pipe
您可以随时实例化您的实体pipe理器工厂和实体pipe理器。 这是你通常在JSE应用程序中做的事情,对吗?
对于这种应用程序,您通常没有处理JTA事务的容器,对吗? 因此,您使用资源本地事务,并负责手动提交或回滚更改。
对于这种应用程序,当你实体化你的实体pipe理器时,上下文会自动附加到它上面。
根据您的应用程序,您可以决定创build一个全局实体pipe理器,其生命周期与应用程序本身的生命周期相关联。 也就是说,应用程序的整个生命周期都是一个单一的实体pipe理器。 在这种情况下,你的上下文将被你的实体经理创build和销毁。
或者,您可以为您的应用程序用户创build每个对话(即事务)的实体pipe理器。 这种情况下的范围是由您决定的,但您的上下文仍将与您的实体经理一起创build和销毁。