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

