蓝凌EKP产品:Hibernate 中 SessionFactory、Session 与事务的关系

在使用 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 ≈ 确认

清理永远不会等于确认。

八、最佳实践总结(可作为团队规范)

  1. SessionFactory

    • 单例

    • 应用启动时创建

  2. Session

    • 有明确边界

    • 用完必须关闭

  3. Transaction

    • 必须显式提交或回滚

    • 不依赖 close

  4. Spring 项目

    • @Transactional

    • 不手动操作事务和 Session

  5. 非 Web 线程

    • 不依赖 OSIV

    • 手动管理 Session 生命周期

九、结语

Hibernate 的问题,
80% 不是 API 用错,
而是生命周期理解错。

一旦你真正搞清楚:

  • SessionFactory 的"重"

  • Session 的"短"

  • Transaction 的"严"

你会发现:

  • 事务问题少了

  • 连接泄露没了

  • 系统稳定性直接上一个台阶

相关推荐
厦门辰迈智慧科技有限公司4 小时前
城市地下管网全域监测与安全防控整体解决方案
数据库·安全·物联网解决方案·地下管网监测·城市地下管网监测
IT 行者4 小时前
Spring Boot 4.x 安全监控新篇章:基于 ObservationFilterChainDecorator 的可观测性实践
java·spring boot·后端
小肖爱笑不爱笑4 小时前
JDBC Mybatis
数据库·mybatis
pyniu4 小时前
Spring Boot租房管理系统
java·spring boot·后端
野生技术架构师4 小时前
TokenRetryHelper 详解与 Spring Boot 迁移方案
java·spring boot·后端
蚰蜒螟4 小时前
Redis网络层深度解析:数据如何写回客户端
java·开发语言·bootstrap
廋到被风吹走4 小时前
【Java】新特性最佳实践:避坑指南与性能优化
java·性能优化
cookqq4 小时前
MySQL 5.7 大表删除部分数据:.ibd 文件会变小吗?磁盘会释放吗?
数据结构·数据库·mysql
ziyue75754 小时前
idea不能使用低版本插件问题解决
java·ide·intellij-idea
IT 行者4 小时前
告别硬编码!Spring Boot 优雅实现 Controller 路径前缀统一管理
数据库·spring boot·python