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

Ale*_*eev 27 java hibernate jpa

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

首先,它们经常导致LazyInitializationExceptionHibernate.是的,有另一个持久性提供程序,它们不会抛出异常,但我认为它们在一致性方面存在一些问题.考虑一下我们有AB实体有reference(@ManyToOne)A从而B需要非空.

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

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

当您想要将持久性和分离的实体存储在一个实体中时,也会出现问题Set.这这种情况下,你应该总是覆盖equalshashCode,通常看起来很笨拙,因为我看不到一个很好的办法做到这一点.

要让一个独立的实体回到EntityManager你身边应该使用merge哪个是毛躁的.

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

And*_*i I 19

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

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

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

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

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

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

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

  • 我无法理解你的两个例子.为什么以及从哪里获得这些实体?如果您在交易的环境中收到它们,为什么它们会分离?如果您在交易之外收到它们,我们为什么要获得实体而不是DTO? (7认同)

Dar*_*rse 15

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

参考Hibernate DOc

为什么?

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

再次参考Hibernate Doc

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

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

假设用户必须更新表单,您可以通过UserObject获取用户的详细信息,此用户对象是持久的会话.现在,如果用户没有提交表单,您的会话将一直打开,直到服务器会话到期,您需要等待多长时间?如果您使用了getCurrentSession,另一个表单请求在前一个表单请求未提交时出现,那么您现在已经有了脏数据!如果您的对象正在等待为Web服务提供的数据并且花费的时间足够长,您仍会保持会话打开,对象持久会话会怎么样?

  • Hibernate 文档解释了分离状态的动机,但没有解释为什么我需要分离实体。至于我,我通常会扔掉所有独立的实体。此外,我很少使用“detach”和“clear”方法。相反,我让实体在会话关闭时分离,并且我从不重用任何会话的实体。我只是无法理解分离后重用实体的动机。 (2认同)
  • 这种方法对于处理大量对象的罕见情况非常有用,并且持久性存储可能会增长到这样的比例,以至于它开始对性能产生显着影响.如果您知道不再需要附加实体,则可以手动逐出它们,并且可能会阻止必须进入下一步的复杂性,即批量/多次交易. (2认同)