是否对原始类使用某种字节码修改?
或者,也许 Hibernate 通过将给定对象与之前持久化的版本进行比较来获取脏状态?
我在使用复杂对象的 hashCode()
和 equals()
方法时遇到问题。我觉得如果对象有集合成员,计算哈希码会非常慢,而且循环引用也是一个问题。
如果Hibernate不会使用hashCode()
/equals()
来检查脏状态,我想我不应该使用equals()
/ hashCode()
用于实体对象(不是值对象),但我也担心相同的运算符 (==
) 还不够。
所以,问题是:
-
Hibernate 如何知道对象的属性是否发生更改?
-
您是否建议重写复杂对象的hashCode()
/equals()
方法?如果它们包含循环引用怎么办?
还有,
-
hashCode()
/equals()
仅包含 id
字段就足够了吗?
Is it using some kind of byte codes modification to the original classes?
Or, maybe Hibernate get the dirty state by compare the given object with previously persisted version?
I'm having a problem with hashCode()
and equals()
methods for complicated objects. I feel it would be very slow to compute hash code if the object has collection members, and cyclic references are also a problem.
If Hibernate won't use hashCode()
/equals()
to check the dirty state, I guess I should not use equals()
/hashCode()
for the entity object (not value object), but I'm also afraid if the same operator (==
) is not enough.
So, the questions are:
-
How does Hibernate know if a property of an object is changed?
-
Do you suggest to override the hashCode()
/equals()
methods for complicated objects? What if they contains cyclic references?
And, also,
-
Would hashCode()
/equals()
with only the id
field be enough?
发布评论
评论(6)
Hibernate 使用一种名为检查的策略,其基本原理是这样的:当从数据库加载对象时,它的快照将保存在内存中。当会话刷新时,Hibernate 会将存储的快照与当前状态进行比较。如果它们不同,则对象被标记为脏对象,并且合适的 SQL 命令将被排队。如果对象仍然是瞬态的,那么它总是脏的。
资料来源:《Hibernate in Action》一书(附录 B:ORM 实现策略)
但值得注意的是,Hibernate 的脏检查与 equals/hascode 方法无关。 Hibernate 根本不考虑这些方法(除非使用 java.util.Set 的方法,但这与脏检查无关,只与 Collections API 相关) 我之前提到的状态快照类似于值数组。将框架的如此核心部分留给开发人员将是一个非常糟糕的决定(说实话,开发人员不应该关心脏检查)。不用说,equals/hascode 可以根据您的需要以多种方式实现。我建议你阅读引用的书,那里作者讨论了 equals/hascode 实现策略。非常有见地的阅读。
Hibernate uses a strategy called inspection, which is basically this: when an object is loaded from the database a snapshot of it is kept in memory. When the session is flushed Hibernate compares the stored snapshot with the current state. If they differ the object is marked as dirty and a suitable SQL command is enqueued. If the object is still transient then it is always dirty.
Source: book Hibernate in Action (appendix B: ORM implementation strategies)
It's important to notice however that Hibernate's dirty-checking is independent of the methods equals/hascode. Hibernate does not look at these methods at all (except when using java.util.Set's, but this is unrelated to dirty-checking, only to the Collections API) The state snapshot I mentioned earlier is something similar to an array of values. It would be a very bad decision to leave such a core aspect of the framework in the hands of developers (to be honest, developers should not care about dirty-checking). Needless to say that equals/hascode can be implemented in many ways according to your needs. I recommend you to read the cited book, there the author discuss equals/hascode implementation strategies. Very insightful reading.
Hibernate 默认的脏检查机制会将所有当前附加实体的所有映射属性与其初始加载时间值进行匹配。
您可以在下图中更好地可视化此过程:
Hibernate default dirty checking mechanism will match all mapped properties of all currently attached entities against their initial loading-time values.
You can better visualize this process in the following diagram:
Hibernate 进行逐字段检查以确定实体的脏程度。
所以 hashCode/equals 根本不适用。
实际上,Hibernate 进行的逐字段脏检查在性能方面的成本可能相当高。
因此它提供了像 Strategy 或 Interceptor.findDirty() 这样的接口来处理同样的问题。
以下帖子更详细地解释了这一点(以及应用程序完全优化的一些想法):http://prismoskills.appspot.com/lessons/Hibernate/Chapter_20_-_Dirty_checking.jsp
Hibernate does a field-by-field checking to determine the dirtiness of an entity.
So hashCode/equals do not come into the picture at all.
Actually, the field-by-field dirty checking done by Hibernate can be quite costly in terms of performance.
So it provides interfaces like Strategy or Interceptor.findDirty() to handle the same.
Following post explains this in greater detail (alongwith some ideas for applications to optimize it fully): http://prismoskills.appspot.com/lessons/Hibernate/Chapter_20_-_Dirty_checking.jsp
可能值得补充一下,因为这让我分心了一段时间:如果您在持久对象上使用
CustomType
,则equals
用于脏检查。该堆栈来自在 Hibernate 中的自定义数据类型 MyType 的 equals 方法中设置断点,然后触发事务并看到 equals 被调用。
Probably worth adding, as this distracted me for a while: if you are using a
CustomType
on your persistent object,equals
is used for the dirty check.This stack is from setting a breakpoint in the equals method of my custom data type in Hibernate, MyType, then triggering a transaction and seeing the equals being called.
脏检查是否还涉及任何附加的 AttributeConverters?如果 java 对象中的值保持不变,但 AttributeConverter 逻辑发生更改并导致数据库值不同,该怎么办?
因此使用旧的 AttributeConverter 配置读取实体,使用新的 AttributeConverter 配置写入实体。
对于新旧 AttributeConverter,java 对象保持相同,但数据库值由于新旧 AttributeConverter 配置而发生变化。
does the dirty checking also involve any attached AttributeConverters? what if the value in the java object stays the same but the AttributeConverter logic is changed and does lead to different database values.
so read entity with old AttributeConverter config, write entity with new AttributeConverter config.
the java object stays the same for old and new AttributeConverter but the database values changes because of old and new AttributeConverter config.
这很简单——当您通过 id 加载/获取实体对象,然后通过 setter 方法设置其新字段值并关闭会话而不调用 update() 方法时。然后hibernate会自动更新表中改变的值而不影响其他字段。 同时实体对象处于脏状态。
It is simple-- when you load/get entity object by id and then set its new field values by setter method and close session without calling update() method. then hibernate automatically update the changed value in the table without affecting other fields. and at the same time entity object is in dirty state.