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 级别,跨会话共享,需手动开启,支持分布式/持久化存储,适用于读多写少的场景。
相关推荐
神龙天舞200111 小时前
MySQL 备库为什么会延迟好几个小时
android·数据库·mysql
每天都要进步哦16 小时前
SQL单行函数详解:字符、数字、日期、转换与通用函数全解析
数据库·mysql
南凉北往17 小时前
PandasAI连接LLM对MySQL数据库进行数据分析
数据库·mysql·数据分析
【心态好不摆烂】20 小时前
MySQL——复合查询
数据库·mysql
瞬间&永恒~21 小时前
【MySQL】 InnoDB 锁等待排查与并发压测实验
运维·数据库·mysql
烟漠河洛21 小时前
俄罗斯电商3200亿卢布疯长:跨境支付与多平台订单系统架构解析
mysql·php
总捣什么乱11 天前
MySQL MySQL是怎么保证主备一致的?
android·mysql·adb
鹿鸣天涯1 天前
应急响应:MySQL日志分析
mysql·安全·adb·oracle
学编程就要猛1 天前
解析博客系统后端实现
java·mysql·jwt·摘要算法·加盐
momo1 天前
Java+WebAI黑马知识点
java·spring boot·mybatis