在使用 Hibernate / Spring 的项目中,
很多人会混淆 Session、Connection、Transaction 的职责,
甚至误以为「Session 关闭就等于事务提交」。
本文从 底层原理 + 生命周期 的角度,彻底梳理三者的关系,并说明:
为什么 Session 必须关闭、事务必须提交。
一、核心结论先行(给没耐心的读者)
-
SessionFactory
-
全局唯一
-
线程安全
-
用来创建 Session
-
-
Session
-
不是数据库连接
-
但会 持有 一个数据库连接
-
有明确生命周期,必须关闭
-
-
Transaction
-
决定数据是否真正写入数据库
-
只有
commit()才算完成事务
-
-
Session.close() ≠ Transaction.commit()
-
Session 关闭 ≈ 连接释放
-
未提交事务会被 回滚
-
二、SessionFactory 是什么?为什么它是单例
1️⃣ 定义
SessionFactory 是 Hibernate 的核心入口对象:
SessionFactory sessionFactory;
它的职责包括:
-
读取 Hibernate 配置
-
管理二级缓存
-
创建
Session -
管理 JDBC 资源策略
2️⃣ 特点
| 特性 | 说明 |
|---|---|
| 是否线程安全 | ✅ 是 |
| 是否昂贵 | ✅ 创建成本高 |
| 生命周期 | 应用级(启动 → 关闭) |
👉 一个数据库通常只需要一个 SessionFactory
三、Session 是什么?它和 Connection 的真实关系
1️⃣ Session 的本质
Session 是 Hibernate 的"工作单元(Unit of Work)"
它负责:
-
实体的持久化状态管理
-
一级缓存
-
脏数据检查(Dirty Checking)
-
生成 SQL
Session session = sessionFactory.openSession();
2️⃣ Session ≠ Connection(但会持有 Connection)
关系可以理解为:
Session
↓
Connection(来自连接池)
关键点:
-
创建 Session 时不一定占用连接
-
第一次执行 SQL 时才从连接池获取 Connection
-
在默认配置下:
- 一个 Session 通常会绑定一个 Connection
四、Transaction 是什么?它才是"是否入库"的裁判
1️⃣ Transaction 的职责
Transaction 管理的是:
-
事务边界
-
提交(commit)
-
回滚(rollback)
Transaction tx = session.beginTransaction();
2️⃣ flush ≠ commit(这是常见误区)
| 操作 | 含义 |
|---|---|
| flush | SQL 发送到数据库 |
| commit | SQL 真正生效 |
没有 commit,数据不会持久化。
五、三者的完整关系图(强烈建议收藏)
┌─────────────────────┐
│ SessionFactory │ (应用级单例)
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ Session │ (一次会话)
│ 一级缓存 / 状态管理 │
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ Connection │ (数据库连接)
│ autoCommit=false │
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ Transaction │
│ commit / rollback │
└─────────────────────┘
调用顺序必须是:
commit / rollback
→ close Session
→ 连接归还连接池
六、Session 的几种关闭方式(非常重要)
1️⃣ 手动管理 Session(非 Web / Worker 场景)
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
try {
...
tx.commit();
} catch (Exception e) {
tx.rollback();
throw e;
} finally {
session.close(); // 必须
}
✅ 推荐方式
2️⃣ Spring + @Transactional(推荐)
@Transactional
public void save() {
sessionFactory.getCurrentSession().save(entity);
}
-
Session 由 Spring 管理
-
Transaction 自动提交 / 回滚
-
不允许手动 close Session
3️⃣ OpenSessionInViewFilter(Web 场景)
请求开始
打开 Session
Service 层提交事务
请求结束
关闭 Session
七、为什么一定要关闭 Session?(这是重点)
1️⃣ 不关闭 Session 的直接后果
-
数据库连接不释放
-
一级缓存无限增长
-
数据库锁无法释放
-
连接池耗尽
👉 工程上表现为"连接泄露"
2️⃣ 事务未提交 + Session 未关闭 = 生产事故
conn.setAutoCommit(false);
// 执行 SQL
// 没 commit
// 没 close
结果:
-
数据回滚
-
连接长期占用
-
系统逐渐卡死
3️⃣ 为什么 close 不能代替 commit?
因为 JDBC 规定:
Connection.close() 时,如果事务未提交 → 自动回滚
也就是说:
close ≈ 清理
commit ≈ 确认
清理永远不会等于确认。
八、最佳实践总结(可作为团队规范)
-
SessionFactory
-
单例
-
应用启动时创建
-
-
Session
-
有明确边界
-
用完必须关闭
-
-
Transaction
-
必须显式提交或回滚
-
不依赖 close
-
-
Spring 项目
-
用
@Transactional -
不手动操作事务和 Session
-
-
非 Web 线程
-
不依赖 OSIV
-
手动管理 Session 生命周期
-
九、结语
Hibernate 的问题,
80% 不是 API 用错,
而是生命周期理解错。
一旦你真正搞清楚:
-
SessionFactory 的"重"
-
Session 的"短"
-
Transaction 的"严"
你会发现:
-
事务问题少了
-
连接泄露没了
-
系统稳定性直接上一个台阶