简体   繁体   English

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

[英]Why need detached entities in JPA?

There are always so many questions related to issues with detached entities! 关于分离实体的问题总是有很多问题!

First, they often cause LazyInitializationException in Hibernate. 首先,它们经常在Hibernate中导致LazyInitializationException Yes, there are another persistence providers, which don't throw exceptions, but I think that they have some problems with consistency. 是的,有另一个持久性提供程序,它们不会抛出异常,但我认为它们在一致性方面存在一些问题。 Consider we have A and B entities that there is reference ( @ManyToOne ) from A to B that is required to be non-null. 考虑我们有AB实体,从AB有引用( @ManyToOne ),需要非空。

We started our session, loaded A instance and then closed session. 我们开始了会话,加载了A实例,然后关闭了会话。 After that we try to obtain a reference to B . 之后我们尝试获得对B的引用。 And assume that another transaction just deleted both our A and B instances. 并假设另一个事务刚刚删除了我们的AB实例。 So when we query from database we can't find appropriate B instance and get null ! 所以当我们从数据库查询时,我们找不到合适的B实例并获得null

So our contract is violated. 所以我们的合同被违反了。 Some code that relies on fact that a.getB() returns an object will throw an NullPointerException . 一些依赖于a.getB()返回对象这一事实的代码将抛出NullPointerException With persistent entities this is impossible because we have all lazy loading in the same transaction with obtaining object itself, so all operations are atomic (if we have a proper transaction isolation of course). 对于持久化实体,这是不可能的,因为我们在获取对象本身的同一事务中具有所有延迟加载,因此所有操作都是原子的(如果我们当然有正确的事务隔离)。

Also there are problems when you want to store persistent and detached entities in one Set . 当您想要在一个Set存储持久性和分离的实体时,也会出现问题。 It that case you should always override equals and hashCode , which usually looks awkward, as I can't see a really good way to do it. 在这种情况下,你应该总是覆盖equalshashCode ,这通常看起来很尴尬,因为我看不到一个非常好的方法。

To get a detached entity back into EntityManager you should use merge which is glitchy. 要将分离的实体重新放回EntityManager您应该使用gligy的merge

So my question is: is there is a reasonable scenario where detached entities are really needed? 所以我的问题是:是否存在真正需要分离实体的合理方案? Furthermore, when do you have to mix detached and persistent entities and merge detached entities into a new EntityManager ? 此外,何时需要混合分离的和持久的实体并将分离的实体合并到新的EntityManager

I will explain why that scenario should not occur and why we need detached entities. 我将解释为什么不应该出现这种情况以及为什么我们需要分离的实体。

Consider you are in a JTA transaction (JPA requires support for it) and fetch a . 考虑一下你在JTA事务中(JPA需要支持它)并获取a Now you can call a.getB() either (1) in this transaction (ie entity a is managed) or (2) when a is detached. 现在,你可以调用a.getB()在本次交易(即实体a被管理)或(2)当a被分离。

Scenario 1 : now depending on your transaction isolation level, you might see or might not see what other transactions do. 场景1 :现在,根据您的事务隔离级别,您可能会看到或可能看不到其他事务的作用。 For example, if you have the SERIALIZABLE isolation level, then you will successfully fetch a.getB() , even if that row was deleted in a concurrent transaction. 例如,如果您具有SERIALIZABLE隔离级别,那么即使在并发事务中删除了该行,您也将成功获取a.getB() If that row was already deleted and your transaction sees that, it means that either your DB is inconsistent (no foreign key) or that you used the wrong transaction isolation level. 如果该行已被删除且您的事务看到了这一行,则表示您的数据库不一致(没有外键)或您使用了错误的事务隔离级别。

Scenario 2 : the entity a is detached. 场景2 :实体a被分离。 When a LazyInitializationException is thrown, that means to me that you called a.getB() too late in order to guarantee a consistence in your application (as a is not managed anymore). 当一个LazyInitializationException被抛出,这意味着对我说,你叫a.getB()以保证您的应用程序的一致性(如来不及了a不再被管理)。 In order to solve the problem you simply call it earlier when the entity is still managed. 为了解决这个问题,您只需在实体仍处于管理状态时更早地调用它。 A NPE cannot occur. NPE不会发生。

Why we need the DETACHED STATE? 为什么我们需要DETACHED STATE? Well, we need a state in which the changes to an entity instance are not tracked. 好吧,我们需要一个不跟踪实体实例更改的状态。 Why? 为什么?

Example 1 : suppose you receive an entity (with persistent identity) in the EJB layer and that there were no detached state (meaning all entities should be managed). 示例1 :假设您在EJB层中收到一个实体(具有持久标识),并且没有分离状态(意味着应该管理所有实体)。 But we need to do a validation before persisting the entity. 但是我们需要在持久化实体之前进行验证。 If that entity would be automatically managed, its changes would be automatically persisted to DB. 如果该实体将被自动管理,其更改将自动保留到DB。 So this new state was introduced. 因此引入了这个新的州。

Example 2 : you receive in the EJB layer an entity, any you need to update ONLY 5 fields of 10 from that entity. 示例2 :您在EJB层中收到一个实体,您需要从该实体仅更新10个10个字段。 If that entity would get automatically into the managed state, all 10 fields would be persisted. 如果该实体将自动进入托管状态,则将保留所有10个字段。 The solution in this case is to fetch a managed entity and to update the 5 fields ONLY in that entity. 在这种情况下,解决方案是获取托管实体并仅在该实体中更新5个字段。

Detached - a detached instance is an object that has been persistent, but its Session has been closed. 已分离 -已分离的实例是一个持久的对象,但其会话已关闭。 The reference to the object is still valid, of course, and the detached instance might even be modified in this state. 当然,对对象的引用仍然有效,甚至可以在此状态下修改分离的实例。 A detached instance can be reattached to a new Session at a later point in time, making it (and all the modifications) persistent again. 可以在稍后的时间点将分离的实例重新附加到新的会话,使其(以及所有修改)再次持久化。 This feature enables a programming model for long running units of work that require user think-time. 此功能为需要用户思考的长时间运行工作单元启用编程模型。 We call them application transactions, ie, a unit of work from the point of view of the user. 我们称之为应用程序事务,即从用户的角度来看工作单元。

References Hibernate DOc 参考Hibernate DOc

Why? 为什么?

The Session caches every object that is in a persistent state (watched and checked for dirty state by Hibernate). Session缓存处于持久状态的每个对象(由Hibernate监视和检查脏状态)。 If you keep it open for a long time or simply load too much data, it will grow endlessly until you get an OutOfMemoryException. 如果你长时间打开它或者只是加载太多数据,它会无休止地增长,直到你得到一个OutOfMemoryException。 One solution is to call clear() and evict() to manage the Session cache,keeping a Session open for the duration of a user session also means a higher probability of stale data. 一种解决方案是调用clear()和evict()来管理会话缓存,在用户会话期间保持会话打开也意味着陈旧数据的概率更高。

References Again Hibernate Doc 再次参考Hibernate Doc

I bet you haven't read through hibernate documentation itself, It has scenarios explaining them too :) 我打赌你没有读过hibernate文档本身,它也有解释它们的场景:)

Simple Explanation:With reference to persistent objects.. 简单说明:引用持久对象..

Suppose a user has to update a form, you get the details of user in from through UserObject, This user object is persistent with session. 假设用户必须更新表单,您可以通过UserObject获取用户的详细信息,此用户对象是持久的会话。 Now if user doesn't submit the form, your session is open until server session expires, how long will you wait? 现在,如果用户没有提交表单,您的会话将一直打开,直到服务器会话到期,您需要等待多长时间? If you have used getCurrentSession, another form request comes while previous one is not submitted, you have got dirty data now!! 如果您使用了getCurrentSession,另一个表单请求未提交前一个表单请求,那么您现在已经有了脏数据! What if your object is waiting for a data that is to come for a web-service and it taking long enough, will you still keep session open, object persistent with session? 如果您的对象正在等待为Web服务提供的数据并且需要足够长的时间,您仍然会保持会话打开,对象持久会话会怎么样?

Detached entities exists only to minimize the time your data is locked due to a transaction, maximizing the number of simultaneous users. 分离的实体仅用于最大程度地减少因事务而导致数据锁定的时间,从而最大限度地提高了并发用户的数量。 Of course, this comes with a cost, and you listed them. 当然,这需要一个成本,你列出了它们。 but since merging conflicts are usually rare, people accept some rare bugs. 但由于合并冲突通常很少,人们会接受一些罕见的错误。

You see, data conflics will always exist, but they occur less when the transaction is short :-) 你看,数据冲突总是存在,但是当交易很短时它们就会发生:-)

It could be that an entity is seen as detached because it has the same ID as an entity in the persistence store. 可能是实体被视为已分离,因为它与持久性存储中的实体具有相同的ID。 Imagine you got the entity from outside of the application. 想象一下,您从应用程序外部获得了实体。 It could be that this entity is seen as detached when trying to persist it. 可能是这个实体在试图坚持它时被视为分离。 There for you have to attach it again with, indeed, the merge. 那里你必须再次附上它,实际上是合并。

I can't really imagine other situations and I'm curious for the other answers. 我无法想象其他情况,我对其他答案感到好奇。

Detached entities (eagerly fetched) could work as DTOs in some cases. 在某些情况下,分离的实体(急切获取)可以作为DTO使用。 Probably not something that should be done in an enterprise application, but eg a java se based network game, where both the server and client come from same codebase, the player state could be reprented as entity and be transfered to/from server and persisted there. 可能不是应该在企业应用程序中完成的事情,但是例如基于java se的网络游戏,其中服务器和客户端都来自相同的代码库,玩家状态可以被重新定义为实体并被转移到服务器并从服务器转移并持久存在。

Not sure that it would be a better choise than proper DTO, but it could be technically done. 不确定它是否比正确的DTO更好,但它可以在技术上完成。

For instance, suppose you have a RESTful interface with a method for retrieving an JSON-serialized object by its id to the caller and a method that receives an updated version of this object from the caller. 例如,假设您有一个RESTful接口,其中有一个方法,用于通过其id向调用者检索JSON序列化对象,以及一个从调用者接收此对象的更新版本的方法。 An entity that passed through such serialization/deserialization will appear in a detached state. 通过此类序列化/反序列化的实体将以分离状态显示。

check this , and read 3.3 merge 检查一下 ,并阅读3.3合并

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM