作者源码阅读笔记主要采用金山云文档记录的,所有的交互图和代码阅读笔记都是记录在云文档里面,本平台的文档编辑实在不方便,会导致我梳理的交互图和文档失去原来的格式,所以整理在文档里面,供大家阅读交流.
【金山文档 | WPS云文档】 SqlSession 会话源码和Executor SQL操作执行器源码
SqlSession
是框架与数据库交互的核心接口。
核心功能
- SQL 操作执行
提供 insert()
、update()
、delete()
、select()
等方法直接执行 SQL 语句,支持参数绑定与结果映射
- 事务管理
通过 commit()
和 rollback()
控制事务提交与回滚,需手动调用(非自动提交模式)
- Mapper 接口代理
通过 getMapper(Class<T> type)
动态生成 Mapper 接口实现类,实现面向对象式数据库操作
- 缓存管理
默认启用一级缓存(会话级),缓存相同 SQL 查询结果,通过 clearCache()
可手动清空。
Executor
包是 MyBatis 执行 SQL 操作的核心引擎,位于 org.apache.ibatis.executor
包下,负责协调 SQL 执行全流程(包括缓存管理、事务控制、参数处理、结果映射等)
Executor
包是 MyBatis 的 SQL 执行中枢,通过多态实现支持基础操作、缓存优化、批量处理等场景,并协调四大组件完成从 SQL 解析到结果映射的全链路操作
核心接口与实现
Executor
接口
定义 SQL 执行的标准方法:
public interface Executor {int update(MappedStatement ms, Object parameter); // 执行更新操作<E> List<E> query(...); // 执行查询操作void commit(boolean required); // 提交事务void rollback(boolean required); // 回滚事务CacheKey createCacheKey(...); // 创建缓存键boolean isCached(MappedStatement ms, CacheKey key); // 检查缓存
}
基础实现类(BaseExecutor
子类)
类型 | 特点 | 适用场景 |
| 默认执行器,每次执行创建新 | 常规单条 SQL 操作 |
| 复用 | 高频重复 SQL |
| 批量执行 SQL,通过 | 批量插入/更新 |
增强实现类 CachingExecutor
- 二级缓存代理:装饰器模式,在基础执行器外层添加二级缓存逻辑
- 工作流程:
- 优先查询二级缓存(
MappedStatement
级别); - 缓存未命中时委托底层执行器(如
SimpleExecutor
)查询数据库
协作组件
Executor 通过组合模式调用其他三大组件:
组件 | 职责 | 依赖关系 |
| 处理 | Executor 调用其执行 SQL |
| 转换参数类型并填充到 | 被 |
| 封装结果集到 Java 对象 | 被 |
相关重要类介绍说明
SqlSessionManager 类
名称 | 描述 | 默认值 |
sqlSessionFactory | 核心作用
| |
sqlSessionProxy |
核心功能
作为 通过
优先从 若未绑定会话(未调用 | |
localSqlSession |
核心作用
通过 避免多线程环境下会话冲突(如事务交叉)
当调用 未调用时字段值为 |
- sqlSessionProxy代理对象创建:
this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(),new Class[] { SqlSession.class }, new SqlSessionInterceptor());
- SqlSessionInterceptor 拦截器
每次调用代理对象 sqlSessionProxy 方法都会去执行invoke方法
private class SqlSessionInterceptor implements InvocationHandler {public SqlSessionInterceptor() {// Prevent Synthetic Access}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();if (sqlSession != null) {try {return method.invoke(sqlSession, args);} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}}try (SqlSession autoSqlSession = openSession()) {try {final Object result = method.invoke(autoSqlSession, args);autoSqlSession.commit();return result;} catch (Throwable t) {autoSqlSession.rollback();throw ExceptionUtil.unwrapThrowable(t);}}}}
SqlSessionFactory sqlSession 工厂类
负责创建和管理 SqlSession
实例
名称 | 描述 | 默认值 |
configuration | 全局配置实例 |
DefaultSqlSession 默认会话类
名称 | 描述 | 默认值 |
configuration | 全局配置实例 | |
executor | sql执行器 | |
autoCommit | 控制事务提交机制的核心参数 | 默认值为 |
dirty | 用于标记当前会话是否存在未提交数据变更的关键状态标识 核心功能
| |
cursorList | 用于管理流式查询游标的关键资源集合 |
所有具体执行器父类 BaseExecutor抽象类
名称 | 描述 | 默认值 |
transaction | 管理数据库事务的核心组件 | |
wrapper |
若未配置装饰器, | |
deferredLoads |
| |
localCache |
典型问题与使用建议
对于不同的sqlsession A与B,A做update操作,只能刷新A自己的一级缓存,无法刷新B的一级缓存。所以如果A与B操作同一条记录,就会有脏读。 SqlSessionB第一查询时进行了缓存,第二次查询时从缓存获取数据(脏数据),之后进行逻辑处理以及更新 | |
localOutputParameterCache |
| |
configuration | 全局配置 | |
queryStack | 控制嵌套查询与延迟加载的关键计数器 典型场景示例
主查询
若 | |
closed | 标识执行器(Executor)是否已被关闭的关键状态标记 |
基于SQL语句复用的执行器 ReuseExecutor 类
通过内部维护的 Map<String, Statement>
缓存(键为 SQL 语句,值为对应的 Statement
对象),避免相同 SQL 的重复编译与创建开销。适用于高频执行相同结构 SQL(如循环中参数化查询)的场景
名称 | 描述 | 默认值 |
statementMap |
|
批量操作执行器 BatchExecutor 类
BatchExecutor
是 MyBatis 中专为批量数据库操作优化的执行器实现,通过延迟执行与批量提交机制显著提升大批量数据操作的性能
名称 | 描述 | 默认值 |
statementList |
工作流程
| |
batchResultList |
| |
currentSql |
| |
currentStatement |
|
二级缓存执行器 CachingExecutor 类
CachingExecutor是一个基于装饰者模式实现的执行器类,主要用于增强二级缓存功能
名称 | 描述 | 默认值 |
delegate |
| |
tcm |
核心职责
确保二级缓存的数据仅在事务成功提交后生效,避免脏读问题。当执行写操作(如 update)时,缓存变更不会立即同步到二级缓存,而是暂存在
管理多个映射语句( 这一设计解决了多 |
TransactionalCacheManager 二级缓存事务管理器
MyBatis 的 TransactionalCacheManager
是二级缓存事务管理的核心组件,主要负责在事务提交时协调多个 TransactionalCache
的缓存同步操作
核心职责
- 事务性缓存控制
管理多个 TransactionalCache
实例,确保二级缓存的更新仅在事务提交后生效,避免事务未提交时其他会话读取到脏数据
- 多缓存空间隔离
通过 Map<String, TransactionalCache>
结构维护不同命名空间(namespace
)的缓存实例,实现缓存区域的隔离与协同
名称 | 描述 | 默认值 |
transactionalCaches | 维护底层真实缓存(如 | Map<Cache, TransactionalCache> |
TransactionalCache 二级事务缓存类
TransactionalCache
是二级缓存事务管理的核心代理类,负责在事务提交前拦截缓存操作,确保数据一致性
核心职责
- 事务暂存区
代理真实的 Cache
对象(如 PerpetualCache
),在事务提交前将写操作(putObject
)暂存于内存,避免未提交事务污染二级缓存
- 脏数据隔离
通过 entriesToAddOnCommit
(待提交数据)和 entriesMissedInCache
(未命中记录)两个集合,隔离事务内外的缓存状态
名称 | 描述 | 默认值 |
delegate |
核心职责 1、真实缓存代理:持有底层缓存实现(如 2、功能扩展基础:通过装饰器模式(如 | |
clearOnCommit | 用于控制事务提交时是否清空底层缓存 | 默认值为 |
entriesToAddOnCommit |
核心职责
| Map<Object, Object> entriesToAddOnCommit |
entriesMissedInCache | 用于追踪二级缓存未命中记录的关键字段,其设计目的主要在于优化并发场景下的缓存一致性与阻塞控制; 记录事务执行过程中缓存查询未命中的键(Key) 该字段是 MyBatis 二级缓存应对高并发穿透问题的核心设计组件之一。 | Set<Object> entriesMissedInCache |
CacheKey 缓存key类
缓存key生成逻辑代码:
@Overridepublic CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {if (closed) {throw new ExecutorException("Executor was closed.");}CacheKey cacheKey = new CacheKey();cacheKey.update(ms.getId());cacheKey.update(rowBounds.getOffset());cacheKey.update(rowBounds.getLimit());cacheKey.update(boundSql.getSql());List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();// mimic DefaultParameterHandler logicMetaObject metaObject = null;for (ParameterMapping parameterMapping : parameterMappings) {if (parameterMapping.getMode() != ParameterMode.OUT) {Object value;String propertyName = parameterMapping.getProperty();if (parameterMapping.hasValue()) {value = parameterMapping.getValue();} else if (boundSql.hasAdditionalParameter(propertyName)) {value = boundSql.getAdditionalParameter(propertyName);} else if (parameterObject == null) {value = null;} else {ParamNameResolver paramNameResolver = ms.getParamNameResolver();if (paramNameResolver != null&& typeHandlerRegistry.hasTypeHandler(paramNameResolver.getType(paramNameResolver.getNames()[0]))|| typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {value = parameterObject;} else {if (metaObject == null) {metaObject = configuration.newMetaObject(parameterObject);}value = metaObject.getValue(propertyName);}}cacheKey.update(value);}}if (configuration.getEnvironment() != null) {// issue #176cacheKey.update(configuration.getEnvironment().getId());}return cacheKey;}
影响key生成的因素:
- Mapper的Id,即Mapper命名空间与<select|update|insert|delete>标签的Id组成的全局限定名
- 查询结果的偏移量及查询的条数
- 具体的SQL语句及SQL语句中需要传递的所有参数
- MyBatis主配置文件中,通过<environment>标签配置的环境信息对应的Id属性值
相关流程图整理
元数据简略图
执行流程图
一级缓存、二级缓存设计与查询流程分析图
- 一级缓存设计-类图
- 一级缓存工作流程图
- 二级缓存设计-类图
- 二级缓存工作流程图