作者源碼閱讀筆記主要采用金山云文檔記錄的,所有的交互圖和代碼閱讀筆記都是記錄在云文檔里面,本平臺的文檔編輯實在不方便,會導致我梳理的交互圖和文檔失去原來的格式,所以整理在文檔里面,供大家閱讀交流.
【金山文檔 | 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屬性值
相關流程圖整理
元數據簡略圖
執行流程圖
一級緩存、二級緩存設計與查詢流程分析圖
- 一級緩存設計-類圖
- 一級緩存工作流程圖
- 二級緩存設計-類圖
- 二級緩存工作流程圖