Hibernate 的 dirty checking(脏检查) 是其核心机制之一,用于在事务提交或 flush() 时自动检测实体对象的属性是否发生了变化,从而决定是否需要向数据库发出 UPDATE 语句。

Dirty Checking 的工作原理如下:

  1. 加载时保存快照:
    当 Hibernate 从数据库加载一个实体对象时,它会为该对象创建一个快照(snapshot),保存当前字段的原始状态,通常是一个内部的 Map 或数组结构。
  2. 对象状态变化:
    当你在代码中对实体对象的属性进行修改(比如 user.setName("Tom")),Hibernate 不会立即执行 SQL 更新,而是等待事务 flush()(自动或手动触发)时统一处理。
  3. 触发 flush 操作:
    在事务提交前(或显式调用 session.flush() 时),Hibernate 会遍历所有持久化状态的实体对象,将当前对象的属性值与快照进行对比。
  4. 差异检测(dirty checking):
    如果发现有字段值与快照不同,说明对象被“脏改动”了,Hibernate 就会生成 UPDATE 语句,仅更新发生变化的字段(视配置而定)。
  5. 更新数据库:
    检测到差异后,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 只更新发生变化的字段,而不是所有字段。