Hibernate 框架从入门到实战:全自动化 ORM 的力量 🔮

Hibernate 是 Java 领域最经典的全自动 ORM(对象关系映射)框架之一,它让开发者彻底告别繁琐的 JDBC 代码,通过对象操作数据库。本文将系统讲解 Hibernate 的核心概念、映射配置、 CRUD 操作、事务管理、HQL 查询语言以及与 Spring 的集成,帮助你全面掌握这门传统但依然重要的持久层技术!💪


📚 目录导航


一、Hibernate 概述:什么是 ORM?

1.1 从 JDBC 到 ORM 的进化

在 JDBC 时代,我们操作数据库是这样的:

  • ❌ 需要手动编写 SQL 语句
  • ❌ 需要手动从 ResultSet 映射到 Java 对象
  • ❌ 需要手动管理数据库连接和资源
  • ❌ SQL 语句散落在代码各处,难以维护

而 ORM 的目标是:让对象和表之间自动映射,你只需要操作对象即可。

1.2 Hibernate 是什么?

Hibernate 是一个全自动的 ORM 框架,它实现了 Java 对象与数据库表之间的自动映射:

Hibernate 的核心优势

  • 全自动映射:Java 对象 ↔ 数据库表,自动转换
  • 无需编写 SQL:框架自动生成并执行 SQL
  • 数据库无关性:切换数据库只需修改配置
  • 缓存支持:内置一级缓存和二级缓存,提升性能
  • 事务管理:提供声明式事务支持
  • 丰富查询:HQL、QBC、原生 SQL 等多种查询方式

1.3 Hibernate vs MyBatis 对比

对比维度 Hibernate MyBatis
映射方式 全自动 半自动
SQL 控制 框架自动生成 手动编写
学习曲线 较陡峭 平缓
灵活性 较低(但足够大多数场景) 高(完全可控)
性能调优 需要深入理解框架 直接优化 SQL
适用场景 业务简单、表结构稳定 复杂查询、性能敏感
国内市场 逐渐减少 绝对主流(+ MyBatis-Plus)

💡 国内现状:MyBatis 因其灵活性和可控性在国内占据主流,但 Hibernate 在企业级应用中仍有广泛应用,特别是在传统行业(如金融、银行)中。选择框架需要根据项目实际需求决定,两者都是值得掌握的技能。


二、环境搭建与配置

2.1 Maven 依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>hibernate-demo</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<hibernate.version>6.3.1.Final</hibernate.version>
<mysql.version>8.0.33</mysql.version>
</properties>

<dependencies>
<!-- Hibernate 核心依赖 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>

<!-- Hibernate JPA 实现(包含 Hibernate EntityManager) -->
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.1.0</version>
</dependency>

<!-- MySQL 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>${mysql.version}</version>
</dependency>

<!-- 数据源 HikariCP(连接池) -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version>
</dependency>

<!-- JUnit 测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>

<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>

<!-- 日志 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.9</version>
</dependency>
</dependencies>
</project>

2.2 创建数据库表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
CREATE DATABASE IF NOT EXISTS hibernate_demo 
DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

USE hibernate_demo;

-- 用户表
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
email VARCHAR(100),
status INT DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 文章表
CREATE TABLE articles (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
title VARCHAR(200) NOT NULL,
content TEXT,
views INT DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 插入测试数据
INSERT INTO users (username, password, email) VALUES
('admin', 'pass123', 'admin@example.com'),
('test', 'pass456', 'test@example.com');

INSERT INTO articles (user_id, title, content, views) VALUES
(1, 'Hibernate 入门', 'Hibernate 是一个优秀的 ORM 框架...', 100),
(1, 'Hibernate 进阶', '本文讲解 Hibernate 的高级特性...', 200),
(2, 'JPA 规范简介', 'JPA 是 Java 持久化 API 规范...', 150);

2.3 hibernate.cfg.xml 全局配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

<!-- SessionFactory:整个应用共享一个 -->
<session-factory>

<!-- ========== 数据库连接配置 ========== -->
<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/hibernate_demo?useSSL=false&amp;serverTimezone=Asia/Shanghai&amp;characterEncoding=utf8
</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">your_password</property>

<!-- 连接池配置(HikariCP) -->
<property name="hibernate.connection.pool_size">10</property>
<property name="hibernate.connection HikariCP minimum-idle">5</property>
<property name="hibernate.connection HikariCP maximum-pool-size">20</property>

<!-- ========== SQL 方言与格式 ========== -->
<!-- 指定数据库方言:Hibernate 会根据方言生成兼容的 SQL -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

<!-- 是否打印 SQL 语句(调试用) -->
<property name="hibernate.show_sql">true</property>

<!-- 是否格式化 SQL(美化输出) -->
<property name="hibernate.format_sql">true</property>

<!-- 是否在控制台打印建表 SQL -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!--
hibernate.hbm2ddl.auto 可选值:
- none:不执行任何操作(默认值)
- create:每次启动创建新表(会删除旧数据)
- create-drop:每次启动创建,关闭删除
- update:更新表结构(推荐开发使用)
- validate:校验映射与表结构是否一致
-->

<!-- ========== 事务配置 ========== -->
<property name="hibernate.transaction.factory_class">
org.hibernate.transaction.JDBCTransactionFactory
</property>

<!-- ========== 缓存配置 ========== -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.internal.EhcacheRegionFactory
</property>

<!-- ========== 当前会话上下文 ========== -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 可选:thread(线程本地)、jta(分布式事务)-->

<!-- ========== 实体映射文件 ========== -->
<mapping resource="com/example/entity/User.hbm.xml"/>
<mapping resource="com/example/entity/Article.hbm.xml"/>

<!-- 或使用注解方式(扫描包) -->
<!-- <mapping class="com.example.entity.User"/> -->

</session-factory>

</hibernate-configuration>

2.4 HibernateUtil 工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.example.util;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
* Hibernate 工具类:管理 SessionFactory
*/
public class HibernateUtil {

// SessionFactory:整个应用只需要一个,轻量级且线程安全
private static final SessionFactory sessionFactory;

static {
try {
// 加载 hibernate.cfg.xml 配置
Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");

// 构建 SessionFactory(耗时长,通常只创建一次)
sessionFactory = configuration.buildSessionFactory();

System.out.println("✅ SessionFactory 初始化成功");

} catch (Exception e) {
throw new RuntimeException("初始化 SessionFactory 失败", e);
}
}

/**
* 获取 SessionFactory
*/
public static SessionFactory getSessionFactory() {
return sessionFactory;
}

/**
* 获取 Session
* Session 是应用程序与数据库的会话,每次操作创建一个
*/
public static Session openSession() {
return sessionFactory.openSession();
}

/**
* 获取当前 Session(线程绑定,无需手动关闭)
* 配合 getCurrentSession 使用,实现事务会话管理
*/
public static Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}

/**
* 关闭 SessionFactory(应用停止时调用)
*/
public static void shutdown() {
if (sessionFactory != null && !sessionFactory.isClosed()) {
sessionFactory.close();
}
}
}

三、实体映射详解

3.1 实体类设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.example.entity;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Builder;

import java.util.Date;

/**
* 用户实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {

private Long id;
private String username;
private String password;
private String email;
private Integer status;
private Date createdAt;
private Date updatedAt;
}

3.2 XML 映射文件(User.hbm.xml)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<!-- class 标签:映射类与表 -->
<class name="com.example.entity.User" table="users">

<!-- id 标签:映射主键 -->
<id name="id" column="id">
<!-- 主键生成策略 -->
<generator class="native"/>
<!--
常见主键生成策略:
- native:数据库自增(MySQL 用 AUTO_INCREMENT)
- identity:支持自增的数据库
- sequence:序列(Oracle、PostgreSQL)
- uuid:UUID 算法生成唯一字符串
- assigned:手动指定 ID
- increment:Hibernate 自增(不推荐集群环境)
-->
</id>

<!-- property 标签:映射普通属性 -->
<property name="username" column="username" not-null="true" unique="true"/>
<property name="password" column="password" not-null="true"/>
<property name="email" column="email"/>

<!-- 类型推断:Hibernate 会自动根据 Java 类型推断 SQL 类型 -->
<!-- 整数的默认值就是 NOT NULL,需要显式指定 nullable -->
<property name="status" column="status">
<column name="status" default="1"/>
</property>

<!-- 日期类型映射 -->
<property name="createdAt" column="created_at"/>
<property name="updatedAt" column="updated_at"/>

</class>
</hibernate-mapping>

3.3 JPA 注解映射(推荐方式)

相比 XML 配置,注解方式更加简洁,是目前主流的选择:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.example.entity;

import jakarta.persistence.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Builder;

import java.util.Date;

/**
* 用户实体类(JPA 注解方式)
*/
@Entity // 声明为实体类
@Table(name = "users") // 映射到哪张表
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {

@Id // 主键
@GeneratedValue(strategy = GenerationType.IDENTITY) // 自增策略
@Column(name = "id") // 映射到哪一列
private Long id;

@Column(name = "username", nullable = false, unique = true)
private String username;

@Column(name = "password", nullable = false)
private String password;

@Column(name = "email")
private String email;

@Column(name = "status")
private Integer status;

@Column(name = "created_at")
@Temporal(TemporalType.TIMESTAMP) // 日期时间类型
private Date createdAt;

@Column(name = "updated_at")
@Temporal(TemporalType.TIMESTAMP)
private Date updatedAt;
}

3.4 主键生成策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 1. 自增(MySQL 推荐)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

// 2. 序列(Oracle、PostgreSQL 推荐)
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq")
@SequenceGenerator(name = "user_seq", sequenceName = "user_sequence", allocationSize = 1)
private Long id;

// 3. TABLE(跨数据库,但性能差)
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "id_gen")
@TableGenerator(name = "id_gen", table = "hibernate_sequences",
pkColumnName = "sequence_name", valueColumnName = "next_val")
private Long id;

// 4. UUID(分布式环境首选)
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private String id; // 使用 String 类型

// 5. AUTO(根据方言自动选择)
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

3.5 属性映射细节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@Entity
@Table(name = "users")
public class User {

// 基本映射(列名默认驼峰转下划线)
private String username;

// 指定列名和约束
@Column(name = "user_name", nullable = false, length = 50, unique = true)
private String userName;

// 插入/更新时忽略字段(不会被保存到数据库)
@Transient
private String temporaryField;

// 枚举类型映射(默认存枚举名)
@Enumerated(EnumType.STRING) // 或 EnumType.ORDINAL 存序号
private UserStatus status;

// 大字段映射
@Lob
private String description; // TEXT 类型

@Lob
private byte[] avatar; // BLOB 类型

// 时间类型
@Temporal(TemporalType.DATE) // 只存日期
@Temporal(TemporalType.TIME) // 只存时间
@Temporal(TemporalType.TIMESTAMP) // 日期时间(默认)
private Date birthDate;
}

// 枚举类
enum UserStatus {
ACTIVE, // 存字符串 "ACTIVE"(@Enumerated(EnumType.STRING))
INACTIVE, // 或存序号 0, 1, 2(@Enumerated(EnumType.ORDINAL))
DELETED
}

四、Hibernate 核心 API

4.1 核心对象关系

API 说明 生命周期
Configuration 加载配置,构建 SessionFactory 应用级别
SessionFactory 创建 Session,重量级,线程安全 应用级别
Session 数据库会话,操作 CRUD 请求级别
Transaction 事务管理 业务方法级别
Query 执行 HQL 查询 查询执行完即可关闭
Criteria 面向对象查询 查询执行完即可关闭

4.2 Session 核心方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Session 接口常用方法

// ===== 增删改 =====
session.save(entity); // 保存(返回主键)
session.persist(entity); // 持久化(无返回值,void)
session.update(entity); // 更新
session.saveOrUpdate(entity); // 保存或更新(根据主键判断)
session.delete(entity); // 删除

// ===== 查询 =====
session.get(Class, id); // 根据主键查询(立即加载)
session.load(Class, id); // 根据主键查询(延迟加载)
session.createQuery(hql); // HQL 查询
session.createCriteria(Class); // QBC 查询
session.createSQLQuery(sql); // 原生 SQL 查询

// ===== 事务 =====
Transaction tx = session.beginTransaction(); // 开启事务
tx.commit(); // 提交事务
tx.rollback(); // 回滚事务

// ===== 其他 =====
session.flush(); // 立即刷新到数据库(同步缓存)
session.clear(); // 清空一级缓存
session.evict(obj); // 从缓存中移除指定对象
session.contains(obj);// 判断对象是否在缓存中
session.close(); // 关闭 Session

4.3 get vs load 区别

1
2
3
4
5
6
7
8
9
10
11
// get 方法:立即加载,查不到返回 null
User user1 = session.get(User.class, 1L);
System.out.println(user1); // 如果不存在,返回 null

// load 方法:延迟加载(代理对象),查不到抛出异常
User user2 = session.load(User.class, 1L);
System.out.println(user2); // 如果不存在,抛出 ObjectNotFoundException

// 实际执行时机:
// - get():调用时立即执行 SELECT 语句
// - load():第一次访问属性时才执行 SELECT 语句(懒加载)
特性 get() load()
加载方式 立即加载 延迟加载(返回代理对象)
查不到时 返回 null 抛出异常
性能 每次都执行 SQL 性能更好(按需加载)
适用场景 确定对象存在 不确定对象是否存在时

五、CRUD 增删改查操作

5.1 插入数据(INSERT)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class HibernateCRUD {

private static SessionFactory factory = HibernateUtil.getSessionFactory();

/**
* 保存用户(save)
*/
public Long saveUser(User user) {
try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();

Long id = (Long) session.save(user); // save() 返回主键

tx.commit();
System.out.println("✅ 用户保存成功,ID:" + id);
return id;
}
}

/**
* 保存用户(persist,无返回值)
*/
public void persistUser(User user) {
try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();

session.persist(user); // persist() 无返回值

tx.commit();
System.out.println("✅ 用户持久化成功");
}
}

/**
* 批量插入(性能优化)
*/
public void batchInsert(List<User> users) {
try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();

for (int i = 0; i < users.size(); i++) {
session.persist(users.get(i));

// 每 20 条刷新一次,释放内存
if (i % 20 == 0) {
session.flush();
session.clear();
}
}

tx.commit();
System.out.println("✅ 批量插入完成,共 " + users.size() + " 条");
}
}
}

5.2 查询数据(SELECT)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
* 根据 ID 查询用户(get)
*/
public User findById(Long id) {
try (Session session = factory.openSession()) {
// get() 立即加载
return session.get(User.class, id);
}
}

/**
* 根据 ID 查询用户(load,延迟加载)
*/
public User findByIdLazy(Long id) {
try (Session session = factory.openSession()) {
// load() 返回代理对象,只有访问属性时才真正查询
User user = session.load(User.class, id);
System.out.println("代理对象已创建:" + user.getClass().getName());
// 只有访问属性时才执行 SELECT
return user;
}
}

/**
* 查询所有用户
*/
public List<User> findAll() {
try (Session session = factory.openSession()) {
Query<User> query = session.createQuery(
"FROM User ORDER BY createdAt DESC", User.class);
return query.list();
}
}

/**
* 条件查询
*/
public List<User> findByStatus(Integer status) {
try (Session session = factory.openSession()) {
Query<User> query = session.createQuery(
"FROM User WHERE status = :status ORDER BY createdAt DESC", User.class);
query.setParameter("status", status);
return query.list();
}
}

/**
* 分页查询
*/
public List<User> findByPage(int page, int size) {
try (Session session = factory.openSession()) {
Query<User> query = session.createQuery(
"FROM User ORDER BY createdAt DESC", User.class);
query.setFirstResult((page - 1) * size); // 起始位置
query.setMaxResults(size); // 每页条数
return query.list();
}
}

5.3 更新数据(UPDATE)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
* 更新用户
*/
public void updateUser(User user) {
try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();

session.update(user);

tx.commit();
System.out.println("✅ 用户更新成功");
}
}

/**
* 更新用户(merge,合并)
*/
public void mergeUser(User user) {
try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();

// merge:合并到持久化上下文,如果缓存中已有则合并,无则从数据库查询
User merged = session.merge(user);

tx.commit();
System.out.println("✅ 用户合并成功");
}
}

/**
* 动态更新(只更新非空字段)
*/
public void dynamicUpdate(Long id, String newEmail) {
try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();

// 先查询
User user = session.get(User.class, id);
if (user != null) {
// 只更新传入的字段
if (newEmail != null && !newEmail.isEmpty()) {
user.setEmail(newEmail);
}
session.update(user); // 只更新非 null 字段对应的列
}

tx.commit();
}
}

/**
* HQL 批量更新
*/
public int batchUpdateStatus(List<Long> ids, Integer newStatus) {
try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();

Query<Integer> query = session.createQuery(
"UPDATE User SET status = :status WHERE id IN :ids", Integer.class);
query.setParameter("status", newStatus);
query.setParameterList("ids", ids);

int rows = query.executeUpdate();
tx.commit();

System.out.println("✅ 批量更新了 " + rows + " 行");
return rows;
}
}

5.4 删除数据(DELETE)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
* 删除用户
*/
public void deleteUser(Long id) {
try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();

// 先查询,再删除
User user = session.get(User.class, id);
if (user != null) {
session.delete(user);
System.out.println("✅ 用户删除成功");
}

tx.commit();
}
}

/**
* 删除用户(直接删除,不需要先查询)
*/
public void deleteUserDirect(Long id) {
try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();

// 创建代理对象(只包含 ID),设置主键后直接删除
User user = new User();
user.setId(id);
session.delete(user);

tx.commit();
System.out.println("✅ 用户删除成功(直接删除)");
}
}

/**
* HQL 批量删除
*/
public int batchDelete(List<Long> ids) {
try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();

Query<Integer> query = session.createQuery(
"DELETE FROM User WHERE id IN :ids", Integer.class);
query.setParameterList("ids", ids);

int rows = query.executeUpdate();
tx.commit();

System.out.println("✅ 批量删除了 " + rows + " 行");
return rows;
}
}

六、对象状态与一级缓存

6.1 Hibernate 对象三种状态

理解 Hibernate 对象状态是掌握 Hibernate 的关键:

6.2 状态转换详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* 瞬时状态(Transient)
* 对象通过 new 创建,与数据库无关联,不在 Session 缓存中
*/
User user = new User();
user.setUsername("test");
user.setPassword("pass"); // user 是瞬时状态

/**
* 持久状态(Persistent)
* 对象被保存(save)后,与数据库记录关联,在 Session 缓存中
*/
session.save(user); // user 变为持久状态

// 特点:
// 1. 对象在 Session 一级缓存中
// 2. 对对象的修改会自动同步到数据库(脏检查)
// 3. 提交事务时会自动 flush 到数据库
user.setEmail("new@example.com"); // 脏检查:自动检测到修改
// session.flush() 或 transaction.commit() 时会执行 UPDATE

/**
* 游离状态(Detached)
* 对象曾经被持久化,但已脱离 Session 管理
* 有 ID,但不在 Session 缓存中
*/
session.close(); // Session 关闭后,之前持久化的对象变为游离状态

// 游离状态对象的复用
User detachedUser = new User();
detachedUser.setId(1L);
detachedUser.setUsername("updated");
session.update(detachedUser); // 重新关联 Session,进入持久状态

6.3 一级缓存机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
* 一级缓存(Session 级别)
* 缓存当前 Session 中所有持久化对象
*/
public void cacheDemo() {
try (Session session = factory.openSession()) {
System.out.println("===== 一级缓存演示 =====");

// 第一次查询:从数据库查询,并放入缓存
User u1 = session.get(User.class, 1L);
System.out.println("第一次查询:" + u1.getUsername());

// 第二次查询:直接从缓存获取(不执行 SQL)
User u2 = session.get(User.class, 1L);
System.out.println("第二次查询:" + u2.getUsername());

// 两次查询返回的是同一个对象(内存地址相同)
System.out.println("是否是同一对象:" + (u1 == u2)); // true

// 强制刷新:清除缓存,从数据库重新查询
session.evict(u1); // 从缓存移除
User u3 = session.get(User.class, 1L);
System.out.println("evict 后查询:" + (u1 == u3)); // false

// 清空所有缓存
session.clear();
}
}

/**
* 脏检查(Dirty Checking)
* Hibernate 自动检测持久化对象的修改,并自动同步到数据库
*/
public void dirtyCheckingDemo() {
try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();

User user = session.get(User.class, 1L);

// 修改用户属性
user.setEmail("dirty@example.com");
user.setStatus(0);
// 此时并未调用 update()!

// 提交事务时会:
// 1. 自动执行 dirty checking(检查所有持久化对象的修改)
// 2. 自动生成 UPDATE 语句
tx.commit();
System.out.println("✅ 脏检查自动更新了用户");
}
}

6.4 flush 机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* flush 模式
* 控制缓存与数据库同步的时机
*/
public void flushDemo() {
try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();

// 设置 flush 模式
// FlushMode.AUTO(默认):在查询前和提交事务前自动同步
// FlushMode.COMMIT:只在提交事务时同步
// FlushMode.ALWAYS:每次查询前都同步
session.setFlushMode(FlushMode.AUTO);

User user = session.get(User.class, 1L);

// 修改后,在新查询前会自动 flush
user.setStatus(0);

// 此处如果不先查询,可以手动 flush
session.flush(); // 立即同步到数据库

tx.commit();
}
}

七、映射关系配置

7.1 一对一关联(@OneToOne)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 用户档案表:一对一关联用户表
*/
@Entity
@Table(name = "user_profiles")
@Data
public class UserProfile {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "real_name")
private String realName;

@Column(name = "id_card")
private String idCard;

@Column(name = "address")
private String address;

@OneToOne(mappedBy = "profile") // 由 User 端维护外键
private User user;
}

/**
* 用户表:一对一关联档案
*/
@Entity
@Table(name = "users")
@Data
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String username;
private String email;

@OneToOne
@JoinColumn(name = "profile_id") // 外键列(users 表)
private UserProfile profile;
}
1
2
3
<!-- XML 方式:一对一映射 -->
<one-to-one name="profile" class="UserProfile" cascade="all"/>
<!-- mappedBy 表示由对方维护外键 -->

7.2 一对多关联(@OneToMany)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* 用户:一对多文章
*/
@Entity
@Table(name = "users")
@Data
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String username;

// 一对多:一方持有多方的集合
// mappedBy:由 Article 端维护外键
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Article> articles = new ArrayList<>();
}

/**
* 文章:多对一作者
*/
@Entity
@Table(name = "articles")
@Data
public class Article {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String title;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id") // 外键列
private User user;
}

7.3 多对多关联(@ManyToMany)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* 教师:多对多学生
*/
@Entity
@Table(name = "teachers")
@Data
public class Teacher {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

// 多对多:中间表 teacher_student
@ManyToMany
@JoinTable(
name = "teacher_student",
joinColumns = @JoinColumn(name = "teacher_id"),
inverseJoinColumns = @JoinColumn(name = "student_id")
)
private Set<Student> students = new HashSet<>();
}

/**
* 学生:多对多教师
*/
@Entity
@Table(name = "students")
@Data
public class Student {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

@ManyToMany(mappedBy = "students") // 由 Teacher 端维护
private Set<Teacher> teachers = new HashSet<>();
}

7.4 级联操作(cascade)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
* 级联操作:操作一个对象时,自动操作关联对象
*/
@Entity
@Table(name = "users")
@Data
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

// cascade 配置:级联类型
// - CascadeType.ALL:所有操作都级联
// - CascadeType.PERSIST:级联保存
// - CascadeType.MERGE:级联合并
// - CascadeType.REMOVE:级联删除
// - CascadeType.REFRESH:级联刷新
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Article> articles = new ArrayList<>();
}

/**
* 级联保存示例:保存用户时自动保存文章
*/
public void cascadeSaveDemo() {
try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();

User user = new User();
user.setUsername("author");
user.setEmail("author@example.com");

Article article = new Article();
article.setTitle("Hibernate 级联操作");
article.setContent("本文讲解级联操作...");
article.setUser(user); // 关联

// 级联保存:只保存 user,自动保存 article
session.save(user);

tx.commit();
System.out.println("✅ 级联保存成功");
}
}

/**
* 级联删除示例:删除用户时自动删除文章
*/
public void cascadeDeleteDemo() {
try (Session session = factory.openSession()) {
Transaction tx = session.beginTransaction();

User user = session.get(User.class, 1L);
session.delete(user); // 级联删除,自动删除关联的文章

tx.commit();
System.out.println("✅ 级联删除成功(用户和文章都删了)");
}
}

八、HQL 查询语言

8.1 HQL 基础语法

HQL(Hibernate Query Language)是面向对象的查询语言,操作的是对象和属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* HQL 查询基础
*/
public void hqlDemo() {
try (Session session = factory.openSession()) {
// 1. 查询所有
Query<User> q1 = session.createQuery("FROM User", User.class);
List<User> users = q1.list();

// 2. 条件查询(命名参数)
Query<User> q2 = session.createQuery(
"FROM User WHERE status = :status ORDER BY createdAt DESC", User.class);
q2.setParameter("status", 1);
List<User> activeUsers = q2.list();

// 3. 条件查询(位置参数)
Query<User> q3 = session.createQuery(
"FROM User WHERE status = ?1 ORDER BY createdAt DESC", User.class);
q3.setParameter(1, 1);

// 4. 分页查询
Query<User> q4 = session.createQuery(
"FROM User ORDER BY createdAt DESC", User.class);
q4.setFirstResult(0); // 起始位置
q4.setMaxResults(10); // 每页条数
List<User> page1 = q4.list();

// 5. 单个查询(uniqueResult)
Query<User> q5 = session.createQuery(
"FROM User WHERE id = :id", User.class);
q5.setParameter("id", 1L);
User user = q5.uniqueResult(); // 确保只有一条记录

// 6. 聚合查询
Query<Long> q6 = session.createQuery(
"SELECT COUNT(*) FROM User", Long.class);
Long count = q6.uniqueResult();

// 7. 投影查询(只查询部分字段,返回 Object[] 或 DTO)
Query<Object[]> q7 = session.createQuery(
"SELECT u.id, u.username, u.email FROM User u", Object[].class);
List<Object[]> results = q7.list();
for (Object[] row : results) {
System.out.println(row[0] + "-" + row[1] + "-" + row[2]);
}
}
}

8.2 HQL 高级特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
* HQL 函数与表达式
*/
public void hqlAdvancedDemo() {
try (Session session = factory.openSession()) {

// 1. 模糊查询
Query<User> q1 = session.createQuery(
"FROM User WHERE username LIKE :kw", User.class);
q1.setParameter("kw", "%test%");

// 2. IN 查询
Query<User> q2 = session.createQuery(
"FROM User WHERE status IN (:statuses)", User.class);
q2.setParameterList("statuses", Arrays.asList(1, 2, 3));

// 3. BETWEEN 查询
Query<User> q3 = session.createQuery(
"FROM User WHERE id BETWEEN :min AND :max", User.class);
q3.setParameter("min", 1L);
q3.setParameter("max", 10L);

// 4. IS NULL / IS NOT NULL
Query<User> q4 = session.createQuery(
"FROM User WHERE email IS NULL OR email = ''", User.class);

// 5. 排序
Query<User> q5 = session.createQuery(
"FROM User ORDER BY createdAt DESC, username ASC", User.class);

// 6. 分组 + 聚合
Query<Object[]> q6 = session.createQuery(
"SELECT u.status, COUNT(u), MAX(u.createdAt) " +
"FROM User u GROUP BY u.status", Object[].class);
List<Object[]> stats = q6.list();
for (Object[] row : stats) {
System.out.println("状态 " + row[0] + ":共 " + row[1] + " 人,最新 " + row[2]);
}

// 7. HAVING 子句
Query<Object[]> q7 = session.createQuery(
"SELECT u.status, COUNT(u) " +
"FROM User u GROUP BY u.status HAVING COUNT(u) > 5", Object[].class);

// 8. 关联查询(JOIN FETCH 预加载)
Query<User> q8 = session.createQuery(
"SELECT DISTINCT u FROM User u " +
"LEFT JOIN FETCH u.articles " +
"WHERE u.id = :id", User.class);
q8.setParameter("id", 1L);
User user = q8.uniqueResult();

// 9. 子查询
Query<User> q9 = session.createQuery(
"FROM User WHERE status = (SELECT MAX(u.status) FROM User u)", User.class);
}
}

8.3 原生 SQL 查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* 原生 SQL 查询
* 当 HQL 无法满足需求时使用
*/
public void nativeSqlDemo() {
try (Session session = factory.openSession()) {

// 1. 原生 SQL 查询(返回实体)
SQLQuery<User> q1 = session.createSQLQuery(
"SELECT * FROM users WHERE status = :status", User.class);
q1.setParameter("status", 1);
List<User> users = q1.list();

// 2. 原生 SQL 返回部分字段(需要添加实体映射)
SQLQuery<Object[]> q2 = session.createSQLQuery(
"SELECT id, username, email FROM users", Object[].class);
List<Object[]> partialUsers = q2.list();

// 3. 调用存储过程
SQLQuery q3 = session.createSQLQuery("CALL get_user_stats()");

// 4. 添加结果集映射
SQLQuery q4 = session.createSQLQuery(
"SELECT u.id, u.username, COUNT(a.id) as article_count " +
"FROM users u LEFT JOIN articles a ON u.id = a.user_id " +
"GROUP BY u.id, u.username");
q4.addScalar("id", LongType.INSTANCE);
q4.addScalar("username", StringType.INSTANCE);
q4.addScalar("article_count", LongType.INSTANCE);
}
}

九、事务管理

9.1 Hibernate 事务概念

9.2 声明式事务(Spring 环境)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Spring + Hibernate 事务管理(推荐)
*/
@Service
@Transactional // 声明式事务
public class UserServiceImpl implements UserService {

@Autowired
private UserRepository userRepository;

@Override
public void transfer(Long fromId, Long toId, BigDecimal amount) {
User from = userRepository.findById(fromId);
User to = userRepository.findById(toId);

from.setBalance(from.getBalance().subtract(amount));
to.setBalance(to.getBalance().add(amount));

userRepository.save(from);
userRepository.save(to);
// 事务会自动提交
}
}

9.3 编程式事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* 原生 Hibernate 事务管理
*/
public void transactionDemo() {
try (Session session = factory.openSession()) {
Transaction tx = null;

try {
// 开启事务
tx = session.beginTransaction();

// 操作 1:保存用户
User user = new User();
user.setUsername("new_user");
user.setPassword("pass");
session.save(user);

// 操作 2:保存文章
Article article = new Article();
article.setTitle("New Article");
article.setUser(user);
session.save(article);

// 操作 3:故意出错(余额不足)
if (user.getBalance().compareTo(amount) < 0) {
throw new RuntimeException("余额不足");
}

// 提交事务
tx.commit();
System.out.println("✅ 事务提交成功");

} catch (Exception e) {
// 发生异常,回滚事务
if (tx != null) {
tx.rollback();
System.out.println("🔄 事务已回滚");
}
throw e;
}
}
}

9.4 事务隔离级别

1
2
3
4
5
6
7
8
9
<!-- hibernate.cfg.xml 配置 -->
<property name="hibernate.connection.isolation">2</property>
<!--
隔离级别:
1 - READ UNCOMMITTED
2 - READ COMMITTED(MySQL 默认)
4 - REPEATABLE READ(MySQL 默认)
8 - SERIALIZABLE
-->

十、延迟加载与抓取策略

10.1 延迟加载(Lazy Loading)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* 延迟加载:只在访问关联对象时才查询
*/
public void lazyLoadingDemo() {
try (Session session = factory.openSession()) {

// 查询用户(不立即查询关联的文章)
User user = session.get(User.class, 1L);
System.out.println("用户:" + user.getUsername());

// 只有访问 articles 时才查询(LazyInitializationException:如果 Session 已关闭)
// user.getArticles() 返回的是代理对象,只有真正访问时才触发查询
List<Article> articles = user.getArticles(); // 触发 SELECT
System.out.println("文章数:" + articles.size());

// 如果 Session 已关闭,访问延迟加载的属性会抛出 LazyInitializationException
}
}

/**
* 解决懒加载异常:使用 Hibernate.initialize()
*/
public void lazyLoadingSolutionDemo() {
try (Session session = factory.openSession()) {
User user = session.get(User.class, 1L);

// 在 Session 关闭前初始化关联对象
Hibernate.initialize(user.getArticles()); // 立即加载

// 或者使用 fetch join 查询时预加载
}
}

10.2 抓取策略(Fetch Strategy)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* 抓取策略配置
*/
@Entity
@Table(name = "users")
@Data
public class User {

// 一对多:默认延迟加载,可配置抓取策略
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private List<Article> articles;

// 批量抓取大小
@BatchSize(size = 20)
private List<Article> articles2;
}

/**
* JOIN FETCH 预加载(推荐)
* 在 HQL 中使用 JOIN FETCH 一次性加载所有数据
*/
public void joinFetchDemo() {
try (Session session = factory.openSession()) {
Query<User> query = session.createQuery(
"SELECT DISTINCT u FROM User u " +
"LEFT JOIN FETCH u.articles " +
"WHERE u.id = :id", User.class);
query.setParameter("id", 1L);

User user = query.uniqueResult();
// 一次查询就加载了 user 和其所有 articles
// 不需要再次查询
}
}

10.3 N+1 问题与解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* N+1 问题示例
*/
public void nPlusOneDemo() {
try (Session session = factory.openSession()) {
// N+1 问题:1 次查询用户 + N 次查询每个用户的文章
List<User> users = session.createQuery("FROM User", User.class).list();

for (User user : users) {
// 每个用户都会触发一次查询文章
System.out.println(user.getUsername() + " - " + user.getArticles().size());
}
// 总共执行 1 + N 次 SQL
}
}

/**
* 解决 N+1 问题:使用 JOIN FETCH
*/
public void solveNPlusOneDemo() {
try (Session session = factory.openSession()) {
// 解决方案:JOIN FETCH 一次性加载
Query<User> query = session.createQuery(
"SELECT DISTINCT u FROM User u " +
"LEFT JOIN FETCH u.articles", User.class);
List<User> users = query.list();

for (User user : users) {
// 不再触发额外查询,直接使用已加载的数据
System.out.println(user.getUsername() + " - " + user.getArticles().size());
}
// 只执行 1 次 SQL
}
}

十一、与 Spring 集成

11.1 Spring + Hibernate 整合配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* Spring 配置 Hibernate(XML 方式)
*/
@Configuration
@EnableTransactionManagement // 开启事务管理
public class HibernateConfig {

@Bean
public LocalSessionFactoryBean sessionFactory(DataSource dataSource) {
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setPackagesToScan("com.example.entity");
factory.setHibernateProperties(hibernateProperties());
return factory;
}

@Bean
public Properties hibernateProperties() {
Properties props = new Properties();
props.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
props.setProperty("hibernate.show_sql", "true");
props.setProperty("hibernate.format_sql", "true");
props.setProperty("hibernate.hbm2ddl.auto", "update");
props.setProperty("hibernate.cache.use_second_level_cache", "true");
return props;
}

@Bean
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
}
}

11.2 Spring Data JPA 简化开发

Spring Data JPA 是 Spring 生态中简化 JPA/Hibernate 开发的利器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* 继承 JpaRepository,自动拥有 CRUD 功能
*/
public interface UserRepository extends JpaRepository<User, Long> {

// 按方法名自动解析查询(无需编写实现)
List<User> findByUsername(String username);

List<User> findByStatus(Integer status);

List<User> findByUsernameContainingAndStatus(String keyword, Integer status);

@Query("FROM User WHERE username = :username")
User findUserByUsername(@Param("username") String username);

@Modifying
@Query("UPDATE User SET status = :status WHERE id = :id")
int updateStatus(@Param("id") Long id, @Param("status") Integer status);
}

/**
* Service 层使用
*/
@Service
@Transactional
public class UserService {

@Autowired
private UserRepository userRepository;

public User getById(Long id) {
return userRepository.findById(id).orElse(null);
}

public List<User> getActiveUsers() {
return userRepository.findByStatus(1);
}

public User getByUsername(String username) {
return userRepository.findUserByUsername(username);
}
}

十二、常见问题与最佳实践

12.1 常见问题与解决方案

12.2 性能优化技巧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* Hibernate 性能优化技巧
*/

// 1. 使用抓取策略减少 SQL 查询
Query<User> query = session.createQuery(
"SELECT DISTINCT u FROM User u " +
"LEFT JOIN FETCH u.articles " +
"WHERE u.id = :id", User.class);

// 2. 使用批量抓取
@OneToMany(mappedBy = "user")
@BatchSize(size = 20)
private List<Article> articles;

// 3. 启用二级缓存
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Entity
@Table(name = "users")
public class User {
// ...
}

// 4. 只查询需要的字段(投影查询)
Query<Object[]> query = session.createQuery(
"SELECT u.id, u.username FROM User u", Object[].class);

// 5. 使用分页查询
Query<User> query = session.createQuery(
"FROM User ORDER BY createdAt DESC", User.class);
query.setFirstResult(0);
query.setMaxResults(20);

// 6. 及时释放资源
try (Session session = factory.openSession()) {
// 操作
} // 自动关闭 Session

12.3 配置清单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- hibernate.cfg.xml 推荐配置 -->
<session-factory>
<!-- SQL 配置 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>

<!-- 性能配置 -->
<property name="hibernate.jdbc.batch_size">20</property>
<property name="hibernate.order_inserts">true</property>
<property name="hibernate.order_updates">true</property>
<property name="hibernate.jdbc.batch_versioned_data">true</property>

<!-- 缓存配置 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property>
</session-factory>

十三、总结

13.1 核心知识点回顾

13.2 学习路线建议

13.3 下一步推荐学习

  • 📖 Spring Data JPA:简化 JPA/Hibernate 开发
  • 📖 MyBatis:对比学习半自动 ORM
  • 📖 Hibernate 源码:理解框架设计思想
  • 📖 数据库优化:索引、SQL 调优
  • 📖 分布式数据库:分库分表、读写分离

💡 写给读者的话:Hibernate 虽然在国内被 MyBatis 盖过了风头,但它在 ORM 领域的经典地位和设计思想依然值得深入学习。理解 Hibernate 的对象状态、缓存机制、延迟加载等核心概念,对你理解其他 ORM 框架甚至整个 Java 持久层生态都有极大帮助。无论是 Hibernate 还是 MyBatis,选择合适的工具做好工作才是最重要的!🚀


📅 本文首次发布于 2026 年 5 月 24 日