MyBatis SqlSession 与缓存机制详解

MyBatis SqlSession 与缓存机制详解


一、Spring 管理下的 SqlSession 核心机制

Spring 会将 SqlSession当前线程事务进行强绑定,这是 MyBatis 整合 Spring 后最核心的运行机制,保证了事务一致性与线程安全。

1. 完整生命周期流程

  1. 事务开启阶段

    Spring 会检查当前线程是否已绑定 SqlSession,若不存在,则创建 SqlSession 并绑定到 ThreadLocal 中,实现线程隔离。

  2. SQL 执行阶段

    所有 Mapper 接口都会通过当前线程绑定的 SqlSession 访问数据库,保证同一事务内使用同一个连接和会话。

  3. 事务/请求结束阶段

    • Spring 事务管理器自动触发 closeSqlSession 逻辑
    • 清空 MyBatis 一级缓存
    • 释放数据库连接(Connection)并归还连接池
    • 解除绑定:将 SqlSession 从当前线程的 ThreadLocal 中移除

2. Mapper 调用底层原理(以 userMapper.selectById(1) 为例)

Mapper 接口本身没有实现类 ,底层是 JDK 动态代理对象,所有调用最终都会交给 SqlSession 执行。

核心代码示意
java 复制代码
// 1. 获取 SqlSession
SqlSession session = sqlSessionFactory.openSession();

// 2. 通过 SqlSession 创建 Mapper 代理对象
UserMapper mapper = session.getMapper(UserMapper.class);

// 3. 本质:调用 SqlSession 的 selectOne 等方法
mapper.selectById(1);

3. Spring 整合后的详细执行流程

第一步:事务前置准备

Spring 事务拦截器 TransactionInterceptor 优先执行:

  1. 通过事务管理器 PlatformTransactionManager 获取数据库连接
  2. 将连接存入 TransactionSynchronizationManager(底层基于 ThreadLocal)
  3. 注意:此阶段仅准备数据库连接,SqlSession 尚未创建
第二步:执行 Mapper 方法(SqlSession 创建时机)

当代码执行到 userMapper.selectById(1) 时:

  1. 进入 Mapper 动态代理对象,调用 SqlSessionTemplate
  2. SqlSessionTemplate 委托 SqlSessionUtils 获取当前会话
  3. 复用/创建规则
    • 线程已有 SqlSession → 直接复用
    • 无线程会话 → 创建新 SqlSession,并绑定到当前 Spring 事务上下文

4. 非事务环境的问题

如果未开启 Spring 事务,执行逻辑会发生变化:

  • 每执行一个 Mapper 方法,Spring 都会创建一个临时 SqlSession
  • 方法执行完毕后立即关闭会话
  • 后果:一级缓存完全失效,多次相同查询会重复访问数据库,性能下降,且无法保证查询结果的数据一致性

二、MyBatis 一级缓存

核心定义

一级缓存是 SqlSession 级别 的缓存,属于默认开启、无法关闭的本地缓存。

工作机制

同一个 SqlSession 内,执行完全相同的 SQL、参数时:

  1. 第一次查询 → 访问数据库,并将结果存入一级缓存
  2. 后续相同查询 → 直接从内存读取,不再请求数据库
  3. 会话提交/关闭/执行增删改操作 → 缓存自动清空

适用场景

单次请求、单次事务内的重复查询优化。


三、MyBatis 二级缓存

核心定义

二级缓存是 Mapper(Namespace)级别 的缓存,跨 SqlSession 共享,多个线程/会话可以访问同一份缓存数据。

工作机制

  1. 当 SqlSession 提交或关闭时,会将一级缓存的数据同步到二级缓存
  2. 其他 SqlSession 执行相同 Mapper 的相同查询时,优先查询二级缓存
  3. 执行增删改操作 → 该 Namespace 下的二级缓存自动清空

开启方式

  1. 全局配置 (默认已开启)

    mybatis-config.xml 中启用缓存开关:

    xml 复制代码
    <setting name="cacheEnabled" value="true"/>
  2. Mapper 配置

    在对应的 Mapper.xml 文件中添加缓存标签:

    xml 复制代码
    <cache/>
  3. 实体类要求

    缓存的 POJO 实体类必须实现 Serializable 序列化接口(二级缓存支持持久化到磁盘、Redis 等存储介质)。


总结

  1. SqlSession:由 Spring 托管,与线程、事务绑定,保证同一事务内会话唯一,非事务环境会导致会话频繁创建销毁、一级缓存失效。
  2. 一级缓存:SqlSession 级别,默认开启,会话内共享,会话关闭即清空。
  3. 二级缓存:Mapper 级别,跨会话共享,需手动开启,支持分布式/持久化存储,适用于读多写少的场景。
相关推荐
云技纵横2 天前
唯一索引 INSERT 死锁实战:5 秒复现交叉插入的 S 锁循环等待
sql·mysql
沉默王二2 天前
面试官:RAG 不用向量数据库,用 MySQL 硬扛?我:100 万向量不是很轻松?
mysql·面试·ai编程
小猿姐3 天前
MySQL Top 10 热点问题 AI 运维实战:从内核诊断到云原生运维
mysql·云原生·aiops
云技纵横3 天前
Gap Lock 死锁实战:5 秒在本地复现 MySQL 间隙锁死锁
后端·mysql
无响应de神3 天前
三、用户与权限管理
数据库·mysql
摇滚侠4 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
ApacheSeaTunnel4 天前
实战演示 | 基于 Apache SeaTunnel 与 Apache DolphinScheduler 实现 MySQL 到 Doris 离线定时增量同步
大数据·mysql·开源·doris·数据集成·seatunnel·数据同步
DARLING Zero two♡4 天前
【MySQL数据库】数据类型与表约束
数据库·mysql