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 级别,跨会话共享,需手动开启,支持分布式/持久化存储,适用于读多写少的场景。
相关推荐
java1234_小锋7 分钟前
【技术专题】Mysql8 数据库 - Mysql8 简介 & 安装以及配置
数据库·mysql
斯内普吖35 分钟前
(开源)水果蔬菜商城实战指南 基于 Java + SSM + Vue + MySQL
java·vue.js·mysql·开源
做运维的阿瑞1 小时前
mysql数据库分组查询:GROUP BY 与 HAVING 的执行逻辑
数据库·sql·mysql
沐欣工作室_lvyiyi2 小时前
基于物联网的智能商业零售管理系统设计与实现(论文+源码)
物联网·mysql·mysql数据库·零售
细嗅蔷薇@2 小时前
DML常见操作
数据库·mysql
青山木3 小时前
秒杀系统设计(二):数据正确性——防超卖、分布式锁与一人一单
分布式·后端·mysql·中间件·架构
ao-weilai3 小时前
MySQL数据库:MySQL基础概要
数据库·mysql
Mortalbreeze4 小时前
MySQL 基础篇(三):一文掌握 MySQL 常见数据类型
linux·服务器·数据库·mysql
夜雪一千16 小时前
MySQL外键彻底入门:是什么、怎么用、什么时候不该用
数据库·mysql
CarIise16 小时前
MyBatis动态SQL:从条件拼接到底层原理实战
mybatis