是否使用某种字节码修改原始类?
或者,也许Hibernate通过将给定对象与先前持久化的版本进行比较来获得脏状态?
我遇到了复杂对象的hashCode()
和equals()
方法的问题。如果对象具有集合成员,并且循环引用也是一个问题,我觉得计算哈希代码会很慢。
如果Hibernate不会使用hashCode()
/ equals()
来检查脏状态,我想我不应该将equals()
/ hashCode()
用于实体对象(不是值)对象),但我也害怕同一个运算符(==
)是不够的。
所以,问题是:
Hibernate如何知道对象的属性是否发生了变化?
您是否建议覆盖复杂对象的hashCode()
/ equals()
方法?如果它们包含循环引用怎么办?
而且,
只有hashCode()
字段的equals()
/ id
是否足够?
答案 0 :(得分:92)
Hibernate使用一种名为 inspection 的策略,基本上就是这样:当从数据库加载一个对象时,它的快照会保存在内存中。刷新会话时,Hibernate会将存储的快照与当前状态进行比较。如果它们不同,则将对象标记为脏,并将合适的SQL命令排入队列。如果对象仍然是瞬态的,那么它总是很脏。
来源:书中的Hibernate in Action(附录B:ORM实施策略)
重要的是要注意Hibernate的脏检查与equals / hascode 方法无关。 Hibernate根本不看这些方法(除了使用java.util.Set时,但这与脏检查无关,只与Collections API无关)我之前提到的状态快照类似于值数组。将框架的这个核心方面留在开发人员手中是一个非常糟糕的决定(说实话,开发人员不应该关心脏检查)。不用说,equals / hascode可以根据您的需要以多种方式实现。我建议你阅读引用的书,作者在那里讨论equals / hascode实现策略。非常有见地的阅读。
答案 1 :(得分:18)
答案 2 :(得分:7)
Hibernate会逐个字段进行检查,以确定实体的肮脏程度。
所以hashCode / equals根本不会出现在图片中。
实际上,Hibernate完成的逐字段脏检查在性能方面可能非常昂贵。
因此它提供了类似Strategy或Interceptor.findDirty()的接口来处理相同的内容。
以下帖子更详细地解释了这一点(以及对优化完全应用的应用的一些想法):http://prismoskills.appspot.com/lessons/Hibernate/Chapter_20_-_Dirty_checking.jsp
答案 3 :(得分:0)
可能值得补充,因为这让我分心了一段时间:如果您在持久对象上使用 CustomType
,则 equals
用于脏检查。
这个栈是从我在Hibernate中自定义数据类型的equals方法中设置断点,MyType,然后触发一个事务,看到equals被调用了。
equals:68, MyType (xxxxxx)
isEqual:105, CustomType (org.hibernate.type)
isSame:119, AbstractType (org.hibernate.type)
isDirty:79, AbstractType (org.hibernate.type)
isDirty:249, CustomType (org.hibernate.type)
findDirty:316, TypeHelper (org.hibernate.type)
findDirty:4622, AbstractEntityPersister (org.hibernate.persister.entity)
dirtyCheck:585, DefaultFlushEntityEventListener (org.hibernate.event.internal)
isUpdateNecessary:242, DefaultFlushEntityEventListener (org.hibernate.event.internal)
onFlushEntity:169, DefaultFlushEntityEventListener (org.hibernate.event.internal)
flushEntities:232, AbstractFlushingEventListener (org.hibernate.event.internal)
flushEverythingToExecutions:92, AbstractFlushingEventListener (org.hibernate.event.internal)
onAutoFlush:50, DefaultAutoFlushEventListener (org.hibernate.event.internal)
accept:-1, 765785095 (org.hibernate.internal.SessionImpl$$Lambda$1238)
fireEventOnEachListener:102, EventListenerGroupImpl (org.hibernate.event.service.internal)
autoFlushIfRequired:1327, SessionImpl (org.hibernate.internal)
答案 4 :(得分:-1)
脏检查是否还包含任何附加的AttributeConverters?如果java对象中的值保持不变但AttributeConverter逻辑已更改并导致不同的数据库值怎么办?
因此,读取具有旧AttributeConverter配置的实体,写入具有新AttributeConverter配置的实体。
对于新旧AttributeConverter,java对象保持不变,但由于新旧AttributeConverter配置,数据库值发生了变化。
答案 5 :(得分:-3)
很简单 - 当您按id加载/获取实体对象,然后通过setter方法和关闭会话设置其新字段值而不调用update()方法。然后,hibernate会自动更新表中更改的值,而不会影响其他字段。 同时实体对象处于脏状态。