Java 为什么需要在 JPA 中分离实体?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21622841/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why need detached entities in JPA?
提问by Alexey Andreev
There are always so many questions related to issues with detached entities!
总是有很多与分离实体相关的问题!
First, they often cause LazyInitializationException
in Hibernate.
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.
首先,它们经常LazyInitializationException
在 Hibernate 中引起。是的,还有另一个持久性提供者,它们不会抛出异常,但我认为它们在一致性方面存在一些问题。考虑到我们拥有A
和B
实体有引用(@ManyToOne
)从A
到B
所需为非空。
We started our session, loaded A
instance and then closed session.
After that we try to obtain a reference to B
.
And assume that another transaction just deleted both our A
and B
instances. So when we query from database we can't find appropriate B
instance and get null
!
我们开始会话,加载A
实例,然后关闭会话。之后,我们尝试获取对 的引用B
。并假设另一个事务刚刚删除了我们的A
和B
实例。所以当我们从数据库中查询时,我们找不到合适的B
实例并得到null
!
So our contract is violated. Some code that relies on fact that
a.getB()
returns an object will throw an 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).
所以我们的合同被违反了。一些依赖于a.getB()
返回对象的事实的代码
将抛出一个NullPointerException
. 对于持久实体,这是不可能的,因为我们在获取对象本身的同一事务中都进行了延迟加载,因此所有操作都是原子的(当然,如果我们有适当的事务隔离)。
Also there are problems when you want to store persistent and detached entities in one 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.
当您想将持久实体和分离实体存储在一个Set
. 在这种情况下,您应该始终覆盖equals
and hashCode
,这通常看起来很尴尬,因为我看不到一个很好的方法来做到这一点。
To get a detached entity back into EntityManager
you should use merge
which is glitchy.
要让一个分离的实体重新进入EntityManager
你应该使用merge
which is glitchy 。
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
?
采纳答案by Andrei I
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
.
Now you can call a.getB()
either (1) in this transaction (i.e entity a
is managed) or (2) when a
is detached.
考虑您在 JTA 事务中(JPA 需要支持它)并 fetch a
。现在您可以a.getB()
在此事务中调用(1)(即实体a
被管理)或 (2) when a
is detached。
Scenario 1: now depending on your transaction isolation level, you might see or might not see what other transactions do. 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. 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.
场景 1:现在取决于您的事务隔离级别,您可能会看到或可能不会看到其他事务的作用。例如,如果您具有 SERIALIZABLE 隔离级别,那么您将成功 fetch a.getB()
,即使该行在并发事务中被删除。如果该行已被删除并且您的事务看到了这一点,则意味着您的数据库不一致(无外键)或您使用了错误的事务隔离级别。
Scenario 2: the entity a
is detached. 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). In order to solve the problem you simply call it earlier when the entity is still managed. A NPE cannot occur.
场景2:实体a
被分离。当 aLazyInitializationException
被抛出时,这对我来说意味着你调用a.getB()
得太晚了,以保证你的应用程序的一致性(因为a
不再管理了)。为了解决这个问题,您只需在实体仍处于管理状态时提前调用它。不会发生 NPE。
Why we need the 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). 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. So this new state was introduced.
示例 1:假设您在 EJB 层收到一个实体(具有持久身份)并且没有分离状态(意味着所有实体都应该被管理)。但是我们需要在持久化实体之前进行验证。如果该实体将被自动管理,其更改将自动保存到 DB。所以引入了这个新状态。
Example 2: you receive in the EJB layer an entity, any you need to update ONLY 5 fields of 10 from that entity. If that entity would get automatically into the managed state, all 10 fields would be persisted. The solution in this case is to fetch a managed entity and to update the 5 fields ONLY in that entity.
示例 2:您在 EJB 层收到一个实体,您需要从该实体更新仅 10 个字段中的 5 个字段。如果该实体将自动进入托管状态,则所有 10 个字段都将被持久化。这种情况下的解决方案是获取托管实体并仅更新该实体中的 5 个字段。
回答by GregD
It could be that an entity is seen as detached because it has the same ID as an entity in the persistence store. 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.
实体可能被视为分离的,因为它与持久性存储中的实体具有相同的 ID。想象一下,您从应用程序外部获得了实体。可能是该实体在尝试持久化时被视为分离的。在那里,您必须再次将其附加到合并中。
I can't really imagine other situations and I'm curious for the other answers.
我真的无法想象其他情况,我很好奇其他答案。
回答by DarkHorse
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, i.e., a unit of work from the point of view of the user.
Detached -分离的实例是一个已经持久化的对象,但它的 Session 已经关闭。当然,对对象的引用仍然有效,并且在这种状态下甚至可能会修改分离的实例。一个分离的实例可以在稍后的时间点重新附加到一个新的 Session,使其(以及所有修改)再次持久化。此功能为需要用户思考时间的长时间运行的工作单元启用编程模型。我们称它们为应用事务,即从用户的角度来看的一个工作单元。
References Hibernate DOc
Why?
为什么?
The Session caches every object that is in a persistent state (watched and checked for dirty state by 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. 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.
Session 缓存每个处于持久状态的对象(由 Hibernate 监视和检查脏状态)。如果长时间保持打开状态或只是加载过多数据,它将无休止地增长,直到出现 OutOfMemoryException。一种解决方案是调用 clear() 和 evict() 来管理 Session 缓存,在用户会话期间保持 Session 打开也意味着陈旧数据的可能性更高。
References Again 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. 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!! 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?
假设用户必须更新表单,您可以通过 UserObject 获取用户的详细信息,此用户对象与会话保持一致。现在,如果用户不提交表单,您的会话将一直打开,直到服务器会话过期,您将等待多长时间?如果你使用了 getCurrentSession,另一个表单请求来了,而前一个没有提交,你现在得到了脏数据!!如果您的对象正在等待 Web 服务的数据,并且花费的时间足够长,您是否仍然保持会话打开,对象与会话持久化?
回答by Leo
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 :-)
你看,数据冲突总是存在的,但是当事务很短时它们发生的更少:-)
回答by Bjarne Bostr?m
Detached entities (eagerly fetched) could work as DTOs in some cases. Probably not something that should be done in an enterprise application, but e.g. 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.
在某些情况下,分离的实体(急切地获取)可以用作 DTO。可能不是应该在企业应用程序中完成的事情,而是例如基于 java se 的网络游戏,其中服务器和客户端都来自相同的代码库,玩家状态可以作为实体重新呈现并传输到/从服务器传输并在那里持久化.
Not sure that it would be a better choise than proper DTO, but it could be technically done.
不确定它是否比适当的 DTO 更好,但可以在技术上完成。
回答by ChengXu
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. An entity that passed through such serialization/deserialization will appear in a detached state.
例如,假设您有一个 RESTful 接口,其中包含一个方法,用于通过调用者的 id 检索 JSON 序列化对象,以及从调用者接收此对象的更新版本的方法。通过这种序列化/反序列化的实体将出现在分离状态。
check this, and read 3.3 merge
检查这个,并阅读3.3合并