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

时间:2014-02-07 08:33:23

标签: java hibernate jpa

关于分离实体的问题总是有很多问题!

首先,它们经常在Hibernate中导致LazyInitializationException。 是的,还有另一个持久性提供程序,它们不会抛出异常,  但我认为他们在一致性方面存在一些问题。 考虑一下我们有AB个实体参考 (@ManyToOne)从AB,必须为非空。

我们开始了会话,加载了A个实例,然后关闭了会话。 之后,我们尝试获取B的引用。 并假设另一个事务刚刚删除了AB个实例。因此,当我们从数据库查询时,我们找不到合适的B实例并获取null

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

如果要在一个Set中存储持久性和分离的实体,也会出现问题。在这种情况下,你应该总是覆盖equalshashCode,这通常看起来很尴尬,因为我看不到一个非常好的方法。

要将分离的实体重新置于EntityManager,您应该使用merge这是一个小问题。

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

6 个答案:

答案 0 :(得分:19)

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

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

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

场景2 :实体a已分离。当抛出LazyInitializationException时,这意味着您为了保证应用程序中的一致性而过晚调用a.getB()(因为a不再受管理)。为了解决这个问题,您只需在实体仍处于管理状态时更早地调用它。 NPE不会发生。

为什么我们需要DETACHED STATE?好吧,我们需要一个不跟踪实体实例更改的状态。为什么?

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

示例2 :您在EJB层中收到一个实体,您只需要从该实体更新10个10个字段。如果该实体将自动进入托管状态,则将保留所有10个字段。在这种情况下,解决方案是获取管理实体并仅更新该实体中的5个字段。

答案 1 :(得分:15)

  

分离 - 分离的实例是一个持久的对象,但其会话已关闭。参考   当然,对象仍然有效,并且分离的实例甚至可能   在这种状态下被修改。分离的实例可以重新附加到a   以后的新会议,制作它(以及所有的   修改)再次坚持。此功能可实现编程   需要用户思考的长期工作单元的模型。我们   称他们为应用程序交易,即来自的工作单位   用户的观点。

参考Hibernate DOc

<强>为什么吗

  

会话缓存处于持久状态的每个对象(观看   并通过Hibernate检查脏状态)。如果你保持开放的话   很长一段时间或只是加载太多数据,它会无休止地增长,直到   你得到一个OutOfMemoryException。一种解决方案是调用clear()和   evict()来管理会话缓存,保持会话打开   用户会话的持续时间也意味着更高的陈旧概率   数据

参考Again Hibernate Doc

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

简单说明:引用持久对象..

  

假设用户必须更新表单,您将获得用户的详细信息   从UserObject,这个用户对象是会话持久的。   现在,如果用户没有提交表单,那么您的会话将一直打开,直到服务器   会话到期,你会等多久?如果你已经使用过   getCurrentSession,另一个表单请求来自前一个   没有提交,你现在有脏数据!如果你的对象是什么   等待即将到来的网络服务数据   你还能保持会话开放,对象持久吗?   会话?

答案 2 :(得分:2)

存在分离的实体只是为了最大限度地减少因事务而导致数据被锁定的时间,从而最大限度地提高了并发用户的数量。当然,这需要一个成本,你列出了它们。但由于合并冲突通常很少见,人们会接受一些罕见的错误。

您可以看到,数据冲突将始终存在,但在事务较短时它们会发生: - )

答案 3 :(得分:0)

可能是实体被视为已分离,因为它与持久性存储中的实体具有相同的ID。想象一下,您从应用程序外部获得了实体。可能是这个实体在试图坚持它时被视为分离。那里你必须再次附上它,实际上是合并。

我无法想象其他情况,我对其他答案感到好奇。

答案 4 :(得分:0)

在某些情况下,分离的实体(急切获取)可以作为DTO使用。可能不是应该在企业应用程序中完成的事情,而是例如一个基于Java se的网络游戏,其中服务器和客户端都来自相同的代码库,玩家状态可以被重新定义为实体并被转移到服务器并从服务器转移并持久存在。

不确定它是否比正确的DTO更好,但它可以在技术上完成。

答案 5 :(得分:0)

例如,假设您有一个RESTful接口,该接口具有一种通过其ID向调用方检索JSON序列化对象的方法,以及一种从调用方接收此对象的更新版本的方法。通过这种序列化/反序列化的实体将以分离状态出现。

选中this,然后阅读3.3合并