EntityManager的find()方法是否创建了JPA类的新实例?

Osw*_*Osw 7 java ejb jpa

我有点困惑.问题在于标题,这就是我要问的原因.我在一个VM上运行JSF + JPA Web应用程序.JPA班有一个@Transient领域.现在想象一些Web用户打开一些页面并执行下面的代码

import javax.persistence.EntityManager;
// method 1 in backing bean
Agent a = entityManager.find(Agent.class, "007");
a.setTransientValue("Aston Martin");
Run Code Online (Sandbox Code Playgroud)

当另一个Web用户/线程尝试读取该瞬态值时,我应该期望什么输出:

// method 2 in backing bean
Agent a = entityManager.find(Agent.class, "007");
String val = a.getTransientValue();
Run Code Online (Sandbox Code Playgroud)

换句话说,就JVM而言,find()方法是否总是返回新的类实例或相同或"它取决于"?我通过JSR-220查看了答案,没有成功,任何帮助或文档参考将不胜感激.

Boz*_*zho 7

如果find(..)在同一会话中调用(即,在相同的entitymanager生命周期内),则将返回相同的对象引用.该的文档find()指定这样的:

如果实体实例包含在持久性上下文中,则从那里返回它.

换句话说,它EntityManager拥有一个实体的集合(最有可能映射).当你调用find它时检查该集合.如果在那里找不到该实体,则进行对数据库的查询.返回的实体被放入地图中,因此后续调用将在那里找到它.

但请再次注意,这仅适用于一个会话的范围.这通常与一个http请求相同(在Web应用程序上下文中)


Edw*_*rzo 5

要真正了解其工作原理,了解实体管理器与上下文之间的关系至关重要.

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

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

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

事务范围

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

@PersistenceContext(unitName="EmployeeService")
EntityManager em;
Run Code Online (Sandbox Code Playgroud)

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

扩展持久化上下文

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

@PersistenceContext(unitName="EmployeeService", type=PersistenceContextType.EXTENDED)
Run Code Online (Sandbox Code Playgroud)

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

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

应用程序托管

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

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

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

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

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