Hibernatedirty 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 只更新发生变化的字段,而不是所有字段。