Java 为什么JPA中需要分离实体?

Java 为什么JPA中需要分离实体?,java,hibernate,jpa,Java,Hibernate,Jpa,总是有那么多与分离实体相关的问题 首先,在Hibernate中,它们通常会导致LazyInitializationException。 是的,还有另一个持久性提供程序,它不会抛出异常, 但我认为它们在一致性方面存在一些问题。 考虑到我们有 < > b>代码>实体,这是有参考价值的。 (@ManyToOne)从A到B,要求非空 我们启动了会话,加载了一个实例,然后关闭了会话。 之后,我们尝试获取对B的引用。 假设另一个事务刚刚删除了A和B实例。所以当我们从数据库中查询时,我们无法找到合适的B实

总是有那么多与分离实体相关的问题

首先,在Hibernate中,它们通常会导致
LazyInitializationException
。 是的,还有另一个持久性提供程序,它不会抛出异常, 但我认为它们在一致性方面存在一些问题。 考虑到我们有<代码> < <代码> > <代码> b>代码>实体,这是有参考价值的。 (
@ManyToOne
)从
A
B
,要求非空

我们启动了会话,加载了一个
实例,然后关闭了会话。
之后,我们尝试获取对
B
的引用。 假设另一个事务刚刚删除了
A
B
实例。所以当我们从数据库中查询时,我们无法找到合适的
B
实例并得到
null

所以我们的合同被违反了。一些代码依赖于以下事实:
a.getB()
返回对象将抛出
NullPointerException
。 对于持久性实体,这是不可能的,因为我们都是懒惰的 与获取对象本身在同一事务中加载, 因此,所有操作都是原子的(当然,如果我们有一个适当的事务隔离)

另外,如果要在一个
集中存储持久和分离的实体,也会出现问题。在这种情况下,您应该始终覆盖
equals
hashCode
,这通常看起来很尴尬,因为我看不到真正好的方法

要将分离的实体返回到
EntityManager
中,您应该使用
merge
,这很容易出错

所以我的问题是:是否存在一个合理的场景,其中真正需要分离的实体?此外,何时必须混合分离实体和持久实体
并将分离的实体合并到一个新的
EntityManager

实体可能被视为分离,因为它与持久性存储中的实体具有相同的ID。假设您从应用程序外部获得实体。可能是在试图持久化该实体时,该实体被视为分离的。因此,您必须再次将其附加到合并中


我真的无法想象其他情况,我对其他答案很好奇。

我将解释为什么不应该出现这种情况,以及为什么我们需要分离的实体

假设您在一个JTA事务中(JPA需要它的支持),并获取
a
。 现在,您可以调用
a.getB()
(1)在此事务中(即实体
a
被管理)或(2)在
a
被分离时

场景1:现在,根据您的事务隔离级别,您可能会看到或看不到其他事务的功能。例如,如果您具有可序列化隔离级别,那么即使该行在并发事务中被删除,您也将成功获取
a.getB()
。如果该行已经被删除,并且您的事务看到了这一点,则表示您的DB不一致(没有外键),或者您使用了错误的事务隔离级别

场景2:实体
a
被分离。当抛出
LazyInitializationException
时,对我来说,这意味着调用
a.getB()
太晚了,无法保证应用程序中的一致性(因为
a
不再被管理)。为了解决这个问题,您只需在实体仍然处于管理状态时调用它。NPE不能发生

为什么我们需要独立的国家?我们需要一种状态,在这种状态下,实体实例的更改不会被跟踪。为什么?

示例1:假设您在EJB层中接收到一个实体(具有持久标识),并且没有分离状态(意味着应该管理所有实体)。但是我们需要在持久化实体之前进行验证。如果该实体将被自动管理,其更改将自动持久化到DB。所以这个新的状态被引入

示例2:您在EJB层收到一个实体,您只需要从该实体中更新5个字段(10个字段)。如果该实体将自动进入托管状态,那么所有10个字段都将被持久化。本例中的解决方案是获取一个托管实体,并仅更新该实体中的5个字段

分离-分离实例是一个已持久化的对象,但其会话已关闭。对 对象仍然有效,当然,分离的实例甚至可能 在这种状态下无法修改。分离的实例可以重新附着到 在稍后的时间点进行新会话,使其(以及所有 修改)再次持续。此功能启用编程 需要用户思考时间的长时间运行的工作单元的模型。我们 将它们称为应用程序事务,即来自 用户的观点

参考资料

为什么?

会话缓存处于持久状态(监视)的每个对象 并通过Hibernate检查脏状态)。如果你把它打开一段时间 长时间或只是加载太多数据,它将无休止地增长,直到 您将得到一个OutOfMemory异常。一种解决方案是调用clear()和 execute()来管理会话缓存,并为会话保持会话打开状态 用户会话的持续时间也意味着过时的可能性更高 数据

参考资料

我打赌您还没有阅读hibernate文档本身,它也有解释它们的场景:)

简单解释:关于持久对象。

假设用户必须更新表单,您可以在 通过UserObject,此用户对象是会话的持久对象。 现在,如果用户不提交表单,您的会话将一直打开到服务器 会话过期,您将等待多长时间?如果你用过 getCurrentSession,另一种形式的re