当前位置: 首页 > 面试题库 >

JPA实体管理器是否应该关闭?

西门山
2023-03-14
问题内容

我有下面的方法。

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

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


问题答案:

我想答案是: 取决于

您的实体管理员是获得对实体所在上下文访问权限的关键。如果您的应用程序是JSE应用程序,则必须考虑上下文的​​预期寿命是多少。

让我们考虑您将根据用户的请求创建一个实体管理器。因此,在您处理给定的请求时,您将保持实体管理器处于打开状态,完成后将其关闭。

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

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

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

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

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

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

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

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

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

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

[…]该EntityManager.close方法关闭实体管理器以释放其持久性上下文和其他资源。调用close之后,应用程序不得在EntityManager实例上调用除getTransaction和之外的任何其他方法
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事务的容器,对吗?因此,您使用本地资源事务,并负责手动提交或回滚更改。

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

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

或者,您可以与您的应用程序用户进行每次对话(即交易)创建一个实体管理器。在这种情况下,范围由您确定,但是仍然可以使用实体管理器来创建和销毁您的上下文。



 类似资料:
  • 实体管理器的上述用法可以吗?或者有必要关闭EM?有什么建议请。

  • 在我的实际应用程序中,我有一个业务层,它根据一些业务规则使用JPA来持久化数据,问题是camel JPA事务没有与业务层事务共享。我需要业务类中的EntityManager与Camel事务范围集成,我该怎么做? 下面是一个简单的例子,但这反映了实际设计中的问题。 项目实例 服务级别 骆驼路线 骆驼背景。xml

  • 我在一个JavaSE项目中使用EclipseLink作为JPA提供者。我已经正确地配置了编织,以允许延迟加载。 与HiberNate(抛出LazyPresalizationExctive)不同,Eclipse Link可以获得LAZY关系的代理,即使是在封闭的实体管理器中。要运行此查询,它从池中获得一个新连接。 是否存在禁用或更改此功能行为的设置?在尝试访问未加载的属性(如Hibernate)时,

  • 我使用的是Spring BOOT应用程序,它将信息存储在数据库中。我得到错误: org.SpringFramework.transaction.CanNotCreateTransactionException:无法为事务打开JPA EntityManager 还尝试了AutoReconnect=true,在db URL中提供了端口号。

  • 我试图使用spring boot将EntityManager注释注入到我的DAO中,但是得到一个< code > InvalidDataAccessApiUsageException 消息,说没有可用的事务EntityManager。我的印象是,只要Spring Boot从< code>application.yml中获得了我的数据源信息,并且我用< code>@PersitenceContext

  • 我正在使用Spring的事务支持和JPA(Hibernate)来持久化我的实体。一切正常,但我在处理一个请求中的部分更新时陷入困境: 对于每个用户(HTTP)请求,我必须将一个日志条目写入数据库表,即使“主”业务实体的更新失败(例如,由于验证错误)。因此,我的第一个/主要事务get被回滚,但第二个(写日志)应该提交。这似乎可以使用正确的传播级别来写入日志条目: 然而,我的问题是,我在第二个事务中注