MyBatis SqlSession 與緩存機制實例詳解
一、Spring 管理下的 SqlSession 核心機制
Spring 會將 SqlSession 與當(dāng)前線程、事務(wù)進(jìn)行強綁定,這是 MyBatis 整合 Spring 后最核心的運行機制,保證了事務(wù)一致性與線程安全。
1. 完整生命周期流程
- 事務(wù)開啟階段
- Spring 會檢查當(dāng)前線程是否已綁定 SqlSession,若不存在,則創(chuàng)建 SqlSession 并綁定到
ThreadLocal中,實現(xiàn)線程隔離。
- Spring 會檢查當(dāng)前線程是否已綁定 SqlSession,若不存在,則創(chuàng)建 SqlSession 并綁定到
- SQL 執(zhí)行階段
- 所有 Mapper 接口都會通過當(dāng)前線程綁定的 SqlSession 訪問數(shù)據(jù)庫,保證同一事務(wù)內(nèi)使用同一個連接和會話。
- 事務(wù)/請求結(jié)束階段
- Spring 事務(wù)管理器自動觸發(fā)
closeSqlSession邏輯 - 清空 MyBatis 一級緩存
- 釋放數(shù)據(jù)庫連接(Connection)并歸還連接池
- 解除綁定:將 SqlSession 從當(dāng)前線程的 ThreadLocal 中移除
- Spring 事務(wù)管理器自動觸發(fā)
2. Mapper 調(diào)用底層原理(以userMapper.selectById(1)為例)
Mapper 接口本身沒有實現(xiàn)類,底層是 JDK 動態(tài)代理對象,所有調(diào)用最終都會交給 SqlSession 執(zhí)行。
核心代碼示意
// 1. 獲取 SqlSession SqlSession session = sqlSessionFactory.openSession(); // 2. 通過 SqlSession 創(chuàng)建 Mapper 代理對象 UserMapper mapper = session.getMapper(UserMapper.class); // 3. 本質(zhì):調(diào)用 SqlSession 的 selectOne 等方法 mapper.selectById(1);
3. Spring 整合后的詳細(xì)執(zhí)行流程
第一步:事務(wù)前置準(zhǔn)備
Spring 事務(wù)攔截器 TransactionInterceptor 優(yōu)先執(zhí)行:
- 通過事務(wù)管理器
PlatformTransactionManager獲取數(shù)據(jù)庫連接 - 將連接存入
TransactionSynchronizationManager(底層基于 ThreadLocal) - 注意:此階段僅準(zhǔn)備數(shù)據(jù)庫連接,SqlSession 尚未創(chuàng)建
第二步:執(zhí)行 Mapper 方法(SqlSession 創(chuàng)建時機)
當(dāng)代碼執(zhí)行到 userMapper.selectById(1) 時:
- 進(jìn)入 Mapper 動態(tài)代理對象,調(diào)用
SqlSessionTemplate SqlSessionTemplate委托SqlSessionUtils獲取當(dāng)前會話- 復(fù)用/創(chuàng)建規(guī)則
- 線程已有 SqlSession → 直接復(fù)用
- 無線程會話 → 創(chuàng)建新 SqlSession,并綁定到當(dāng)前 Spring 事務(wù)上下文
4. 非事務(wù)環(huán)境的問題
如果未開啟 Spring 事務(wù),執(zhí)行邏輯會發(fā)生變化:
- 每執(zhí)行一個 Mapper 方法,Spring 都會創(chuàng)建一個臨時 SqlSession
- 方法執(zhí)行完畢后立即關(guān)閉會話
- 后果:一級緩存完全失效,多次相同查詢會重復(fù)訪問數(shù)據(jù)庫,性能下降,且無法保證查詢結(jié)果的數(shù)據(jù)一致性
二、MyBatis 一級緩存
核心定義
一級緩存是 SqlSession 級別的緩存,屬于默認(rèn)開啟、無法關(guān)閉的本地緩存。
工作機制
在同一個 SqlSession 內(nèi),執(zhí)行完全相同的 SQL、參數(shù)時:
- 第一次查詢 → 訪問數(shù)據(jù)庫,并將結(jié)果存入一級緩存
- 后續(xù)相同查詢 → 直接從內(nèi)存讀取,不再請求數(shù)據(jù)庫
- 會話提交/關(guān)閉/執(zhí)行增刪改操作 → 緩存自動清空
適用場景
單次請求、單次事務(wù)內(nèi)的重復(fù)查詢優(yōu)化。
三、MyBatis 二級緩存
核心定義
二級緩存是 Mapper(Namespace)級別的緩存,跨 SqlSession 共享,多個線程/會話可以訪問同一份緩存數(shù)據(jù)。
工作機制
- 當(dāng) SqlSession 提交或關(guān)閉時,會將一級緩存的數(shù)據(jù)同步到二級緩存
- 其他 SqlSession 執(zhí)行相同 Mapper 的相同查詢時,優(yōu)先查詢二級緩存
- 執(zhí)行增刪改操作 → 該 Namespace 下的二級緩存自動清空
開啟方式
- 全局配置(默認(rèn)已開啟)
- 在
mybatis-config.xml中啟用緩存開關(guān): <setting name="cacheEnabled" value="true"/>
- Mapper 配置
- 在對應(yīng)的
Mapper.xml文件中添加緩存標(biāo)簽: <cache/>
- 實體類要求
- 緩存的 POJO 實體類必須實現(xiàn)
Serializable序列化接口(二級緩存支持持久化到磁盤、Redis 等存儲介質(zhì))。
總結(jié)
- SqlSession:由 Spring 托管,與線程、事務(wù)綁定,保證同一事務(wù)內(nèi)會話唯一,非事務(wù)環(huán)境會導(dǎo)致會話頻繁創(chuàng)建銷毀、一級緩存失效。
- 一級緩存:SqlSession 級別,默認(rèn)開啟,會話內(nèi)共享,會話關(guān)閉即清空。
- 二級緩存:Mapper 級別,跨會話共享,需手動開啟,支持分布式/持久化存儲,適用于讀多寫少的場景。
到此這篇關(guān)于MyBatis SqlSession 與緩存機制詳解的文章就介紹到這了,更多相關(guān)MyBatis SqlSession 緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Mybatis的SqlSession和一級緩存的失效原因分析及解決
- MyBatis?SqlSession執(zhí)行流程小結(jié)
- springboot3集成mybatis-plus報sqlSession異常的問題解決
- MyBatis的通俗理解:SqlSession.getMapper()源碼解讀
- 詳解Mybatis核心類SqlSessionFactory的構(gòu)建
- SpringBoot3整合MyBatis出現(xiàn)異常:Property?'sqlSessionFactory'or?'sqlSessionTemplate'?are?required
- Mybatis SqlSessionFactory與SqlSession詳細(xì)講解
- 使用Mybatis-Plus時的SqlSessionFactory問題及處理
相關(guān)文章
spring boot整合mybatis+mybatis-plus的示例代碼
這篇文章主要介紹了spring boot整合mybatis+mybatis-plus的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01
SpringBoot2.動態(tài)@Value的實現(xiàn)方式
這篇文章主要介紹了SpringBoot2.動態(tài)@Value的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
SpringCloud整合Nacos實現(xiàn)流程詳解
這篇文章主要介紹了SpringCloud整合Nacos實現(xiàn)流程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-09-09
springboot項目用maven插件打包時報錯的解決方法
文章介紹了解決Spring Boot項目使用Maven插件打包時遇到JDK版本無效問題的步驟,本文分步驟給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2026-01-01
Spring中的BeanFactory與FactoryBean區(qū)別詳解
這篇文章主要介紹了Spring中的BeanFactory與FactoryBean區(qū)別詳解,BeanFactory是一個接口,它是spring中的一個工廠,FactoryBean也是一個接口,實現(xiàn)了3個方法,通過重寫其中方法自定義生成bean,需要的朋友可以參考下2024-01-01

