Skip to content

Hibernate 学习路线

Hibernate 是 Java 生态中非常经典的 ORM 框架,也是 JPA 规范的常见实现。它的核心思想是把数据库表映射成 Java 对象,让开发者用对象的方式操作数据。

零基础学习 Hibernate 时,不要只背注解。重点要理解实体状态、持久化上下文、事务边界、懒加载和 N+1 查询问题。

详细全过程建议配合阅读 Hibernate/JPA 核心全过程原理,那里会把实体状态、脏检查、flush、commit、懒加载、N+1 和商业排查串成一条完整链路。

Hibernate 解决什么问题

如果直接使用 JDBC,开发者需要手动:

  1. 写 SQL。
  2. 设置参数。
  3. 执行查询。
  4. 遍历 ResultSet。
  5. 把每一列映射到 Java 对象。
  6. 管理连接和事务。

Hibernate 会自动处理对象和表之间的映射,并在事务提交时同步对象变化。

Hibernate 和 MyBatis 的区别

对比HibernateMyBatis
关注点对象模型和持久化上下文SQL 可控性
SQL框架自动生成较多开发者手写较多
学习重点实体状态、关联、懒加载参数映射、动态 SQL、结果映射
适合场景领域模型清晰、CRUD 多SQL 复杂、报表多
风险N+1、懒加载、隐式 SQLSQL 维护成本

实际项目里没有绝对优劣,要看团队习惯和业务复杂度。

学习路线

mermaid
flowchart TD
    A["实体映射"] --> B["主键和字段映射"]
    B --> C["实体状态"]
    C --> D["持久化上下文"]
    D --> E["事务和脏检查"]
    E --> F["关联关系"]
    F --> G["懒加载和 N+1"]
    G --> H["JPQL、Criteria、原生 SQL"]
    H --> I["性能优化"]

实体映射

一个简单实体:

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

    @Column(name = "user_name")
    private String userName;

    private Integer age;
}

注解说明:

注解作用
@Entity标记为实体类
@Table指定表名
@Id主键
@GeneratedValue主键生成策略
@Column字段和列映射

实体状态

Hibernate 中实体对象有状态。

mermaid
flowchart TD
    A["Transient 瞬时态"] --> B["Persistent 持久态"]
    B --> C["Detached 游离态"]
    B --> D["Removed 删除态"]
状态说明
Transient新创建对象,未和数据库关联
Persistent被持久化上下文管理
Detached曾被管理,但 Session 已关闭
Removed标记为删除

理解状态很重要,因为只有持久态对象才会被脏检查自动同步。

持久化上下文

持久化上下文可以理解成 Hibernate 的一级缓存和对象管理区。

它负责:

  1. 保存当前事务中加载的实体。
  2. 保证同一个主键只对应一个对象实例。
  3. 进行脏检查。
  4. 在 flush 时同步 SQL。

脏检查

脏检查 Dirty Checking 指 Hibernate 自动检测对象属性变化。

java
User user = entityManager.find(User.class, 1L);
user.setUserName("新名字");
// 不需要显式 update,事务提交时 Hibernate 会自动生成 update SQL

这很方便,但也意味着你要清楚事务边界,避免无意中修改实体导致更新数据库。

关联关系

常见关联:

  1. 一对一 @OneToOne
  2. 一对多 @OneToMany
  3. 多对一 @ManyToOne
  4. 多对多 @ManyToMany

建议:

  1. 不要为了对象完整而滥用双向关联。
  2. 多对多通常拆成中间实体更清晰。
  3. 列表查询不要直接加载大量关联集合。

懒加载和 N+1

懒加载表示关联数据在真正访问时才查询。

N+1 问题示例:

  1. 先查询 1 次文章列表。
  2. 遍历每篇文章时,再查询作者。
  3. 如果有 N 篇文章,就额外查询 N 次。
mermaid
flowchart TD
    A["查询文章列表 1 次"] --> B["遍历文章"]
    B --> C["每篇文章查询作者"]
    C --> D["总共 1 + N 次查询"]

解决思路:

  1. 使用 fetch join。
  2. 使用 EntityGraph。
  3. 使用批量加载。
  4. 查询 DTO。
  5. 对列表接口控制分页。

Controller 不要直接返回实体

实体通常包含关联关系,直接返回可能导致:

  1. 懒加载异常。
  2. JSON 序列化循环引用。
  3. 暴露不该返回的字段。
  4. 触发额外 SQL。

建议转换 DTO。

使用建议

  1. 简单 CRUD 可以使用 Hibernate/JPA。
  2. 复杂报表查询可以使用原生 SQL 或 MyBatis。
  3. 事务边界放在 Service 层。
  4. 列表查询必须分页。
  5. 关注 SQL 日志,避免隐式 N+1。

本章小结

Hibernate 的重点不是注解本身,而是实体状态、持久化上下文、脏检查、关联关系和懒加载。学会看 Hibernate 生成的 SQL,才能真正用好它。

核心原理

Hibernate 的核心机制可以概括为:实体映射表结构,持久化上下文管理实体状态,事务提交时通过脏检查生成 SQL。

mermaid
flowchart TD
    A["Entity 映射表"] --> B["Persistence Context"]
    B --> C["管理实体状态"]
    C --> D["事务提交"]
    D --> E["脏检查生成 SQL"]

这解释了为什么 Hibernate 写 CRUD 很快,但复杂关联和性能问题必须看最终 SQL。

下一步阅读:Hibernate/JPA 核心全过程原理