Skip to content

hibernate

参考文档:Hibernate. Everything data.

帮助:Hibernate 中文文档 | Hibernate 中文网

Hibernate 是什么

Hibernate 是一个完整 ORM 框架,它通过实体类和表结构的映射,让开发者以面向对象的方式操作数据库。相比 MyBatis,Hibernate 更强调对象状态管理、自动脏检查、级联关系和缓存能力。

如果要从零理解它为什么能自动更新、为什么会懒加载异常、为什么会出现 N+1,先看 Hibernate/JPA 核心全过程原理。这页总览负责建立概念,深度页负责解释完整执行过程。

核心概念

概念说明
Entity和数据库表映射的实体对象
Session持久化上下文,负责对象状态跟踪
Transaction事务边界
Persistence Context一级缓存和脏检查发生的位置
HQL/JPQL面向实体对象的查询语言
Criteria类型安全、动态构造查询条件

实体状态流转

mermaid
stateDiagram-v2
    [*] --> Transient: new 对象
    Transient --> Persistent: save/persist
    Persistent --> Detached: session close/clear
    Detached --> Persistent: merge/update
    Persistent --> Removed: remove/delete
    Removed --> [*]: flush 到数据库

实体对象常见状态:

  1. Transient:临时状态,只存在于内存,没有数据库记录。
  2. Persistent:持久化状态,被 Session 管理,修改后会被脏检查发现。
  3. Detached:游离状态,有数据库标识,但已经不被当前 Session 管理。
  4. Removed:删除状态,事务提交或 flush 后删除数据库记录。

Hibernate 执行更新的流程

mermaid
flowchart TD
    A[查询实体] --> B[实体进入持久化上下文]
    B --> C[业务代码修改字段]
    C --> D[事务提交或 flush]
    D --> E[脏检查比较快照]
    E --> F{字段是否变化}
    F -- 是 --> G[生成 update SQL]
    F -- 否 --> H[不执行更新]
    G --> I[同步到数据库]

优点和成本

方面说明
优点减少重复 CRUD、对象关系建模自然、缓存和脏检查能力强
成本学习曲线更高、SQL 不够直观、复杂查询容易产生性能问题

常见性能问题

  1. N+1 查询:查询列表后又逐条懒加载关联对象。
  2. 级联范围过大:保存一个对象时意外更新大量关联数据。
  3. 懒加载失效:Session 关闭后访问懒加载属性导致异常。
  4. 自动生成 SQL 不符合预期:索引使用差、关联过多。
  5. 大批量写入不清理上下文:一级缓存占用过多内存。

使用建议

  1. 实体关联不要为了“对象完整”而无限双向关联。
  2. 查询列表页时优先使用 DTO 投影,避免加载大对象图。
  3. 对关键 SQL 打开日志并配合执行计划分析。
  4. 批量导入、复杂报表、强 SQL 优化场景可以使用原生 SQL。
  5. 如果团队主要使用 Spring Data JPA,需要理解 Hibernate 是其常见底层实现。

深入学习路线

学习顺序内容目标
1Hibernate/JPA 核心全过程原理理解持久化上下文、实体状态、脏检查、flush、懒加载和 N+1
2Hibernate 学习路线建立 Hibernate 的整体学习路径
3JPA 基础理解 JPA 规范和 EntityManager
4Spring Data JPA理解 Repository 封装和查询方式
5Spring Data JPA 事务与分页掌握事务边界、DTO 转换、分页 count 和深分页风险

代码 Demo:实体和脏检查

java
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;

    public void changeUsername(String username) {
        this.username = username;
    }
}
java
@Service
public class HibernateUserService {
    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    public void changeUsername(Long id, String username) {
        User user = entityManager.find(User.class, id);
        user.changeUsername(username);
        // 不需要手写 update,事务提交时 Hibernate 会脏检查并生成 SQL。
    }
}

这个 Demo 体现了 Hibernate 和 MyBatis 的差异:Hibernate 关注实体状态,MyBatis 更关注显式 SQL。

为什么 Hibernate 要看最终 SQL

Hibernate 的原理是根据实体状态、关联关系和持久化上下文生成 SQL。它提高了 CRUD 效率,但也可能因为懒加载、关联映射、级联配置生成超出预期的 SQL。

如果不看最终 SQL,容易出现:

  1. 列表查询触发 N+1。
  2. 修改一个实体导致级联更新过多数据。
  3. 事务外访问懒加载字段报错。
  4. 分页查询 count SQL 很慢。

所以 Hibernate 不是“不用关心 SQL”,而是“通过对象操作减少模板代码,同时必须关注生成 SQL 是否合理”。