Hibernate 学习指南

1. Hibernate 核心概念与价值

1.1 什么是 Hibernate?

Hibernate 是一个全自动 ORM(对象-关系映射)框架,它负责 Java 对象与关系型数据库表之间的映射,允许开发者通过操作对象来实现数据库 CRUD,无需手动编写 SQL 语句。

它是 JPA(Java Persistence API)规范的主要实现者,同时提供了远超 JPA 规范的扩展功能。

1.2 为什么选择 Hibernate?

  • 彻底屏蔽 SQL:通过对象操作自动生成 SQL,减少重复劳动
  • 跨数据库兼容:支持 MySQL、Oracle、SQL Server 等,切换数据库无需修改代码
  • 强大的关联映射:轻松处理复杂的对象关系(如订单-商品-用户的多对多关联)
  • 内置缓存机制:一级缓存(Session 级别)、二级缓存(SessionFactory 级别)提升性能
  • 与 Spring 生态无缝集成:在 Spring 项目中可通过@Repository轻松整合

1.3 Hibernate 与其他 ORM 框架的区别

框架 特点对比 适用场景
Hibernate 全自动 ORM,无需写 SQL,学习曲线较陡 复杂关系、快速开发、跨库需求
MyBatis 半自动化 ORM,需手动写 SQL,灵活性高 需优化 SQL、互联网高并发场景
Spring Data JPA 基于 JPA 的封装,简化 CRUD 接口 快速开发简单业务

2. 环境搭建与第一个程序

2.1 核心依赖(Maven)

<!-- Hibernate核心包 -->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.6.14.Final</version>
</dependency>
<!-- 数据库驱动(以MySQL为例) -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.30</version>
</dependency>
<!-- 日志框架(可选,用于调试) -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.36</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.11</version>
</dependency>

</dependencies>

2.2 核心配置文件(hibernate.cfg.xml)

放置在src/main/resources目录下,配置数据库连接和Hibernate基础属性:<?xml version=”1.0” encoding=”UTF-8”?>
<!DOCTYPE hibernate-configuration PUBLIC
“-//Hibernate/Hibernate Configuration DTD 3.0//EN”
http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">




com.mysql.cj.jdbc.Driver
jdbc:mysql://localhost:3306/hibernate_demo?serverTimezone=UTC
root
123456

    <!-- 方言:指定数据库类型(Hibernate根据方言生成对应SQL) -->
    <property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>

    <!-- 可选配置 -->
    <property name="hibernate.show_sql">true</property> <!-- 显示生成的SQL -->
    <property name="hibernate.format_sql">true</property> <!-- 格式化SQL -->
    <property name="hibernate.hbm2ddl.auto">update</property> <!-- 自动建表策略 -->

    <!-- 注册实体类(包扫描或具体类) -->
    <mapping class="com.example.entity.User"/>
</session-factory>

</hibernate-configuration>
hbm2ddl.auto参数说明

  • create:每次启动删除旧表,创建新表(测试用)
  • create-drop:启动创建表,关闭时删除(测试用)
  • update:根据实体类自动更新表结构(开发用)
  • validate:校验表结构与实体类是否一致,不一致报错(生产用)

2.3 第一个 Hibernate 程序:保存用户

步骤 1:创建实体类(User.java)package com.example.entity;

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
import javax.persistence.*;
import java.time.LocalDateTime;

@Entity // 标记为Hibernate实体
@Table(name = "t_user") // 映射到数据库表t_user
public class User {
@Id // 主键
@GeneratedValue(strategy = GenerationType.IDENTITY) // 自增策略
private Long id;

@Column(name = "username", length = 50, nullable = false) // 映射到字段username
private String username;

@Column(name = "create_time")
private LocalDateTime createTime;

// 构造方法、getter、setter
public User() {}
public User(String username) {
this.username = username;
this.createTime = LocalDateTime.now();
}

// getter和setter省略...
}

步骤 2:编写测试类 package com.example.test;

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
import com.example.entity.User;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class HibernateDemo {
public static void main(String[] args) {
// 1. 加载配置文件,创建SessionFactory(重量级对象,全局只需要一个)
SessionFactory sessionFactory = new Configuration()
.configure("hibernate.cfg.xml")
.buildSessionFactory();

// 2. 获取Session(轻量级对象,类似数据库连接)
Session session = sessionFactory.openSession();

// 3. 开启事务
Transaction transaction = session.beginTransaction();

try {
// 4. 业务操作:保存用户
User user = new User("张三");
session.save(user); // Hibernate自动生成INSERT语句

// 5. 提交事务
transaction.commit();
System.out.println("保存成功,用户ID:" + user.getId());
} catch (Exception e) {
// 异常时回滚事务
transaction.rollback();
e.printStackTrace();
} finally {
// 6. 关闭资源
session.close();
sessionFactory.close();
}
}
}

执行结果

  • 控制台输出自动生成的 SQL:
    1
    insert into t_user (create_time, username) values (?, ?)
  • 数据库表t_user中新增一条记录,id自动递增。

3. 实体映射基础(注解与 XML)

Hibernate 支持两种映射方式:注解映射(推荐)和XML 映射(传统方式),核心是定义”类 → 表”、”属性 → 字段”的对应关系。

3.1 常用注解详解

注解 作用 常用属性
@Entity 标记类为 Hibernate 实体 -
@Table 指定映射的表名 name:表名;schema:数据库名
@Id 标记属性为主键 -
@GeneratedValue 主键生成策略 strategy:生成策略(如 IDENTITY)
@Column 映射属性到表字段 name:字段名;length:长度;nullable:是否允许为空
@Transient 标记属性不映射到数据库(临时属性) -
@Temporal 映射日期时间类型(JPA 规范) valueTemporalType.DATE/TIME/TIMESTAMP

主键生成策略(@GeneratedValue

  • GenerationType.IDENTITY:依赖数据库自增(MySQL 的 AUTO_INCREMENT)
  • GenerationType.SEQUENCE:使用数据库序列(Oracle 的 SEQUENCE)
  • GenerationType.TABLE:通过中间表生成主键(跨数据库通用)
  • GenerationType.AUTO:由 Hibernate 自动选择(默认)

3.2 XML 映射方式(备用方案)

当需要避免在实体类中混入注解时,可使用 XML 映射文件(如User.hbm.xml):<?xml version=”1.0” encoding=”UTF-8”?>

<!DOCTYPE hibernate-mapping PUBLIC
“-//Hibernate/Hibernate Mapping DTD 3.0//EN”
http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">





    <!-- 普通属性映射 -->
    <property name="username" column="username" length="50" not-null="true"/>
    <property name="createTime" column="create_time"/>
</class>

</hibernate-mapping>需在hibernate.cfg.xml中注册映射文件:

4. 核心 API 详解(Session、Transaction 等)

Hibernate 的核心操作围绕以下 API 展开,理解它们的生命周期和用法是关键。

4.1 SessionFactory

  • 作用:创建 Session 对象,维护数据库连接信息和 Hibernate 配置
  • 特点:重量级对象,线程安全,全局只需要一个实例
  • 创建方式
    1
    2
    3
    SessionFactory sessionFactory = new Configuration()
    .configure() // 默认加载hibernate.cfg.xml
    .buildSessionFactory();

4.2 Session

  • 作用:类似数据库连接,负责执行 CRUD 操作,管理实体对象的生命周期
  • 特点:轻量级对象,线程不安全,每次操作需创建新实例
  • 核心方法
    • save(obj):保存对象(生成 INSERT)
    • get(clazz, id):根据 ID 查询(立即加载)
    • load(clazz, id):根据 ID 查询(懒加载,返回代理对象)
    • update(obj):更新对象(生成 UPDATE)
    • delete(obj):删除对象(生成 DELETE)
    • saveOrUpdate(obj):保存或更新(根据 ID 是否为 null 自动判断)
    • createQuery(hql):创建 HQL 查询对象

4.3 Transaction

  • 作用:管理事务,保证操作的原子性
  • 核心方法
    • commit():提交事务
    • rollback():回滚事务
  • 使用规范:所有数据库操作必须在事务中执行(即使是查询,也建议开启事务以保证一致性)

4.4 实体对象的三种状态

Hibernate 中实体对象有三种状态,状态转换是理解缓存和持久化的关键:

  1. 瞬时态(Transient)

    • 特点:未与 Session 关联,数据库中无对应记录,无主键 ID
    • 例:new User("张三")创建的对象
    • 转换:调用session.save()→ 持久态
  2. 持久态(Persistent)

    • 特点:与 Session 关联,数据库中存在对应记录,有主键 ID
    • 例:session.get(User.class, 1L)查询到的对象
    • 特性:对对象的修改会自动同步到数据库(脏检查机制)
  3. 脱管态(Detached)

    • 特点:曾是持久态,但 Session 已关闭,数据库中存在对应记录
    • 转换:session.close()后持久态 → 脱管态;调用session.update()→ 重新变为持久态

5. 查询方式全解析(HQL、Criteria、SQL)

Hibernate 提供多种查询方式,满足不同场景需求。

5.1 HQL(Hibernate Query Language)

特点:面向对象的查询语言,语法类似 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
32
33
34
35
36
37
38
39
40
41
42
43
44
Query<User> query = session.createQuery("from User", User.class);
List<User> users = query.getResultList();

// 条件查询(占位符参数)
Query<User> query = session.createQuery(
"from User where username like :name", User.class);
query.setParameter("name", "%张%"); // 命名参数
List<User> users = query.getResultList();

// 分页查询
query.setFirstResult(0); // 起始索引(从0开始)
query.setMaxResults(10); // 每页条数
#### 投影查询(只查询部分字段)// 返回Object数组(包含username和createTime)
Query<Object[]> query = session.createQuery(
"select username, createTime from User", Object[].class);
List<Object[]> results = query.getResultList();

// 返回Map(需Hibernate 5.2+)
Query<Map<String, Object>> query = session.createQuery(
"select new map(username as name, createTime as time) from User", Map.class);
#### 聚合查询// 统计用户总数
Query<Long> countQuery = session.createQuery(
"select count(id) from User", Long.class);
Long total = countQuery.getSingleResult();

// 分组查询
Query<Object[]> groupQuery = session.createQuery(
"select username, count(id) from User group by username", Object[].class);
### 5.2 Criteria API( Criteria查询)
**特点**:纯面向对象的查询API,无需写字符串查询语句,通过方法链构建查询条件(Hibernate 5.2+推荐使用JPA的Criteria API)。
// 创建Criteria查询对象
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> root = cq.from(User.class); // 根实体

// 构建条件:username like %张% 且 id > 10
Predicate condition = cb.and(
cb.like(root.get("username"), "%张%"),
cb.gt(root.get("id"), 10L)
);
cq.where(condition);

// 执行查询
List<User> users = session.createQuery(cq).getResultList();

5.3 原生 SQL 查询

特点:直接执行原生 SQL 语句,适合复杂查询场景(如多表关联、数据库特有函数)。

1
2
3
4
5
6
7
8
9
10
11
12
// 原生SQL查询
Query<Object[]> query = session.createSQLQuery(
"select username, create_time from t_user where id > :id");
query.setParameter("id", 5L);
List<Object[]> results = query.getResultList();

// 原生SQL映射到实体类
Query<User> query = session.createSQLQuery(
"select * from t_user where username like :name")
.addEntity(User.class) // 指定映射的实体类
.setParameter("name", "%李%");
List<User> users = query.getResultList();

6. 关联映射(一对一、一对多、多对多)

关联映射是 Hibernate 的核心优势,用于处理对象之间的关系(对应数据库的外键关联)。

6.1 一对多关联(最常用)

场景:一个用户(User)有多个订单(Order),一个订单属于一个用户。

步骤 1:定义实体类// User.java(一的一方)

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
@Entity
@Table(name = "t_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;

// 一对多关联:一个用户有多个订单
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Order> orders = new ArrayList<>();

// 添加订单的便捷方法(维护关联关系)
public void addOrder(Order order) {
orders.add(order);
order.setUser(this); // 双向关联需设置反向引用
}

// getter、setter省略
}

// Order.java(多的一方)
@Entity
@Table(name = "t_order")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String orderNo;

// 多对一关联:多个订单属于一个用户(外键在订单表)
@ManyToOne(fetch = FetchType.LAZY) // 懒加载:查询订单时不自动查询用户
@JoinColumn(name = "user_id") // 外键字段名
private User user;

// getter、setter省略
}

关键属性说明:

  • mappedBy = "user":指定关联关系由 Order 类的 user 属性维护(外键在 t_order 表)
  • cascade = CascadeType.ALL:级联操作(保存用户时自动保存订单,删除用户时自动删除订单)
  • orphanRemoval = true:当订单从用户的 orders 列表中移除时,自动删除该订单
  • fetch = FetchType.LAZY:懒加载(查询订单时不加载用户,访问 user 属性时才查询)

步骤 2:测试一对多关联// 保存用户及关联的订单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

User user = new User("张三");
Order order1 = new Order("ORDER001");
Order order2 = new Order("ORDER002");

user.addOrder(order1); // 维护关联关系
user.addOrder(order2);

session.save(user); // 因cascade=ALL,会自动保存订单

tx.commit();
session.close();

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
**场景**:一个用户(User)对应一个用户详情(UserDetail)。
// User.java
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;

// 一对一关联(共享主键)
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
private UserDetail detail;
// getter、setter省略
}

// UserDetail.java
@Entity
public class UserDetail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String address;

// 一对一关联(外键在UserDetail表,引用User的id)
@OneToOne
@PrimaryKeyJoinColumn // 共享主键(UserDetail的id = User的id)
private User user;
// getter、setter省略
}

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
**场景**:一个学生(Student)可以选多门课程(Course),一门课程有多个学生。
// Student.java
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;

// 多对多关联:中间表student_course
@ManyToMany(cascade = CascadeType.PERSIST)
@JoinTable(
name = "student_course", // 中间表名
joinColumns = @JoinColumn(name = "student_id"), // 本表外键
inverseJoinColumns = @JoinColumn(name = "course_id") // 关联表外键
)
private Set<Course> courses = new HashSet<>();
// getter、setter省略
}

// Course.java
@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String courseName;

// 多对多反向关联
@ManyToMany(mappedBy = "courses")
private Set<Student> students = new HashSet<>();
// getter、setter省略
}

7. 缓存机制(一级、二级、查询缓存)

Hibernate 的缓存机制是提升性能的关键,减少数据库访问次数。

7.1 一级缓存(Session 缓存)

  • 作用范围:当前 Session(会话)级别,生命周期与 Session 一致
  • 特点:默认开启,无法关闭,线程不安全
  • 工作原理:Session 会缓存查询到的持久态对象,同一 Session 内再次查询相同 ID 的对象时,直接从缓存获取,不查询数据库
1
2
3
4
5
6
7
8
9
Session session = sessionFactory.openSession();

// 第一次查询:从数据库加载,放入一级缓存
User user1 = session.get(User.class, 1L);

// 第二次查询:从一级缓存获取,不查数据库
User user2 = session.get(User.class, 1L);

System.out.println(user1 == user2); // true(同一对象)

7.2 二级缓存(SessionFactory 缓存)

  • 作用范围:整个应用级别,所有 Session 共享
  • 特点:默认关闭,需手动配置,线程安全
  • 适用场景:查询频繁、修改少的数据(如字典表、分类表)

步骤 1:添加二级缓存依赖(以 Ehcache 为例)

1
2
3
4
    <groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.6.14.Final</version>
</dependency>

步骤 2:配置二级缓存

hibernate.cfg.xml中添加:

true org.hibernate.cache.ehcache.EhCacheRegionFactory true

步骤 3:标记实体类使用二级缓存@Entity

1
2
3
4
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) // 缓存策略
public class User {
// ... 字段省略
}

缓存策略(CacheConcurrencyStrategy

  • READ_ONLY:只读(适合不会修改的数据)
  • READ_WRITE:读写(支持修改,保证一致性)
  • NONSTRICT_READ_WRITE:非严格读写(可能出现脏读,性能高)
  • TRANSACTIONAL:事务型(分布式环境使用)

7.3 查询缓存

  • 作用:缓存 HQL/Criteria 查询的结果集
  • 特点:依赖二级缓存,需手动开启并指定查询使用缓存
    // 开启查询缓存
    Query query = session.createQuery(“from User”, User.class);
    query.setCacheable(true); // 此查询结果会被缓存

// 第一次查询:从数据库加载,结果放入查询缓存
List users1 = query.getResultList();

// 第二次查询:从查询缓存获取
List users2 = query.getResultList();

8. 事务管理与并发控制

8.1 事务 ACID 特性

Hibernate 事务严格遵循 ACID 特性:

  • 原子性(Atomicity):事务中的操作要么全成,要么全败
  • 一致性(Consistency):事务执行前后数据状态一致
  • 隔离性(Isolation):多个事务并发执行时互不干扰
  • 持久性(Durability):事务提交后数据永久保存

8.2 事务隔离级别

hibernate.cfg.xml中配置:

4隔离级别对应值:

  • 1:READ_UNCOMMITTED(读未提交,可能脏读)
  • 2:READ_COMMITTED(读已提交,避免脏读)
  • 4:REPEATABLE_READ(可重复读,避免脏读、不可重复读)
  • 8:SERIALIZABLE(串行化,避免所有并发问题,性能低)

8.3 并发控制:乐观锁与悲观锁

乐观锁(推荐)

通过版本号控制并发,适合读多写少场景:@Entity

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer stock;

// 版本号字段(乐观锁核心)
@Version
private Integer version; // 每次更新自动加1

// getter、setter省略
}
  • 原理:更新时会检查版本号,update ... where id=? and version=?
  • 冲突时:抛出OptimisticLockingFailureException,需重试

悲观锁

通过数据库锁机制控制,适合写多读少场景:// 使用 HQL 加悲观锁

1
2
3
4
Query<User> query = session.createQuery("from User where id=:id", User.class);
query.setParameter("id", 1L);
query.setLockMode(LockMode.PESSIMISTIC_WRITE); // 悲观写锁(排他锁)
User user = query.getSingleResult();

9. 高级特性(批量操作、拦截器、事件)

9.1 批量操作(提高大量数据处理效率)

默认情况下,Hibernate 会逐条处理数据,批量操作可优化性能:

批量插入 Session session = sessionFactory.openSession();

Transaction tx = session.beginTransaction();

for (int i = 0; i < 1000; i++) {
User user = new User(“用户” + i);
session.save(user);

// 每50条刷新一次并清理缓存(避免内存溢出)
if (i % 50 == 0) {
    session.flush(); // 刷入数据库
    session.clear(); // 清理一级缓存
}

}

tx.commit();
session.close();
需在hibernate.cfg.xml中添加批量配置:50

true

9.2 拦截器(Interceptor)

用于在实体对象生命周期的特定阶段(如保存、更新前)插入自定义逻辑:
public class MyInterceptor extends EmptyInterceptor {
// 保存前拦截
@Override
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
if (entity instanceof User) {
// 自动设置创建时间
for (int i = 0; i < propertyNames.length; i++) {
if (“createTime”.equals(propertyNames[i])) {
state[i] = LocalDateTime.now();
return true; // 通知 Hibernate 状态已修改
}
}
}
return false;
}
}
注册拦截器:SessionFactory sessionFactory = new Configuration()
.configure()
.setInterceptor(new MyInterceptor()) // 全局拦截器
.buildSessionFactory();

9.3 事件监听(Event Listener)

类似拦截器,更灵活的生命周期事件处理:
public class UserSaveListener implements PreInsertEventListener {
@Override
public boolean onPreInsert(PreInsertEvent event) {
if (event.getEntity() instanceof User) {
// 设置创建时间
event.getState()[event.getPersister()
.getPropertyIndex(“createTime”)] = LocalDateTime.now();
}
return false; // 不阻止事件继续执行
}
}
注册监听器(在hibernate.cfg.xml中):


</event>

10. 性能优化实践

10.1 减少数据库访问

  • 合理使用缓存(一级缓存默认开启,二级缓存用于高频查询数据)
  • 批量操作替代逐条操作(设置hibernate.jdbc.batch_size
  • 分页查询避免一次性加载大量数据(setFirstResult+setMaxResults

10.2 优化关联查询

  • 优先使用懒加载(FetchType.LAZY),避免不必要的关联数据加载
  • 复杂关联查询使用fetch join(HQL)一次性加载所需数据,避免 N+1 查询问题:
    1
    2
    3
    4
    5
    // 一次性加载用户及其订单(避免N+1查询)
    List<User> users = session.createQuery(
    "from User u left join fetch u.orders where u.id = :id", User.class)
    .setParameter("id", 1L)
    .getResultList();

10.3 其他优化建议

  • 关闭hibernate.hbm2ddl.auto(生产环境),手动管理表结构
  • 使用DTO模式传输数据,避免返回完整实体类
  • 避免在循环中执行数据库操作
  • 合理设置Session生命周期(Web 项目中通常与请求生命周期一致)

11. 实战案例:完整 CRUD 应用

11.1 项目结构 src/main/java

├── com.example
│ ├── entity
│ │ └── User.java
│ ├── dao
│ │ ├── UserDao.java
│ │ └── UserDaoImpl.java
│ ├── service
│ │ ├── UserService.java
│ │ └── UserServiceImpl.java
│ └── util
│ └── HibernateUtil.java
src/main/resources
└── hibernate.cfg.xml

11.2 核心代码实现

Hibernate 工具类(HibernateUtil.java)public class HibernateUtil {

private static final SessionFactory sessionFactory;

static {
    try {
        // 初始化SessionFactory
        sessionFactory = new Configuration()
                .configure()
                .buildSessionFactory();
    } catch (Throwable ex) {
        throw new ExceptionInInitializerError(ex);
    }
}

public static SessionFactory getSessionFactory() {
    return sessionFactory;
}

public static void shutdown() {
    getSessionFactory().close();
}

}

DAO 层(UserDaoImpl.java)public class UserDaoImpl implements UserDao {

@Override
public void save(User user) {
    Session session = HibernateUtil.getSessionFactory().openSession();
    Transaction tx = null;
    try {
        tx = session.beginTransaction();
        session.save(user);
        tx.commit();
    } catch (Exception e) {
        if (tx != null) tx.rollback();
        e.printStackTrace();
    } finally {
        session.close();
    }
}

@Override
public User getById(Long id) {
    Session session = HibernateUtil.getSessionFactory().openSession();
    try {
        return session.get(User.class, id);
    } finally {
        session.close();
    }
}

// 其他CRUD方法省略...

}

Service 层与测试(略)

12. 常见问题与解决方案

12.1 N+1 查询问题

现象:查询 N 个主对象时,每个主对象都触发一次关联对象查询,共执行 N+1 次 SQL。
解决:使用fetch join一次性加载关联数据:from User u left join fetch u.orders where u.id in (:ids)

12.2 懒加载异常(LazyInitializationException)

现象:Session 关闭后访问懒加载的关联属性(如order.getUser())。
解决

  • 方法 1:在 Session 关闭前初始化关联对象(Hibernate.initialize(order.getUser())
  • 方法 2:使用fetch = FetchType.EAGER(不推荐,可能加载过多数据)
  • 方法 3:延长 Session 生命周期(如 Web 项目中使用 Open Session In View 模式)

12.3 事务提交后数据未更新

原因:实体对象处于脱管态(Session 已关闭),修改后未调用update()
解决:重新关联 Session 并更新:Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = session.merge(detachedUser); // 合并脱管对象到 Session
tx.commit();
session.close();

12.4 缓存与数据库数据不一致

原因:二级缓存未及时更新。
解决

  • 修改数据后手动清理缓存:sessionFactory.getCache().evict(User.class, id)
  • 使用合适的缓存策略(如READ_WRITE