Hibernate 的 dirty checking(脏检查) 是其核心机制之一,用于在事务提交或 flush() 时自动检测实体对象的属性是否发生了变化,从而决定是否需要向数据库发出 UPDATE 语句。
Dirty Checking 的工作原理如下:
- 加载时保存快照:
当 Hibernate 从数据库加载一个实体对象时,它会为该对象创建一个快照(snapshot),保存当前字段的原始状态,通常是一个内部的Map或数组结构。 - 对象状态变化:
当你在代码中对实体对象的属性进行修改(比如user.setName("Tom")),Hibernate 不会立即执行 SQL 更新,而是等待事务flush()(自动或手动触发)时统一处理。 - 触发 flush 操作:
在事务提交前(或显式调用session.flush()时),Hibernate 会遍历所有持久化状态的实体对象,将当前对象的属性值与快照进行对比。 - 差异检测(dirty checking):
如果发现有字段值与快照不同,说明对象被“脏改动”了,Hibernate 就会生成UPDATE语句,仅更新发生变化的字段(视配置而定)。 - 更新数据库:
检测到差异后,Hibernate 执行相应的 SQL 语句同步数据。
示例
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = session.get(User.class, 1);
user.setName("Tom"); // 修改了 name 字段
tx.commit(); // commit 时会触发 flush -> dirty checking -> 执行 UPDATE
session.close();
小结
| 步骤 | 动作 |
|---|---|
| 1 | 加载实体,Hibernate 记录字段快照 |
| 2 | 修改实体属性,Hibernate 不立即更新数据库 |
| 3 | 事务提交或 flush(),Hibernate 比较快照和当前状态 |
| 4 | 有变化则执行 SQL 更新 |
注意事项
- Hibernate 只能检测通过 setter 方法或字段直接修改的属性。
- 如果你使用了绕过 Hibernate 的手段修改(比如反射或直接修改底层结构),可能不会被检测到。
- 配置
@DynamicUpdate可以让 Hibernate 只更新发生变化的字段,而不是所有字段。


苏公网安备32021302001419号