MyBatis提供查詢緩存,如果緩存中有數(shù)據(jù)作烟,則直接從緩存中獲取,沒有則從數(shù)據(jù)庫查詢砾医,用以減輕數(shù)據(jù)壓力拿撩,提高系統(tǒng)性能。MyBatis的緩存分為一級(jí)緩存和二級(jí)緩存如蚜,默認(rèn)情況下一級(jí)緩存是開啟的压恒,且是不能關(guān)閉的。一級(jí)緩存是SqlSession級(jí)別的错邦,當(dāng)同一個(gè) SqlSession中進(jìn)行相同的sql查詢時(shí)探赫,第二次以后的查詢都是從一級(jí)緩存中獲取,一級(jí)緩存最多緩存1024條sql撬呢。二級(jí)緩存是Mapper級(jí)別的伦吠,可以跨SqlSession,不同SqlSession可共享。
MyBatis緩存機(jī)制
MyBatis緩存實(shí)現(xiàn)原理
MyBatis認(rèn)為的完全相同的查詢魂拦,只要保證statementId毛仪,rowBounds,最后生成的SQL語句,以及這個(gè)SQL語句所需要的參數(shù)完全一致就可以了晨另。
一級(jí)緩存
一級(jí)緩存是如何組織的潭千?
一級(jí)緩存是SqlSession級(jí)別的緩存。在操作數(shù)據(jù)庫時(shí)需要構(gòu)造 sqlSession對(duì)象借尿,并為SqlSession對(duì)象創(chuàng)建一個(gè)Executor執(zhí)行器刨晴,而緩存信息以HashMap的形式維護(hù)在這個(gè)Executor中,MyBatis將緩存和緩存操作封裝在Cache中路翻。
一級(jí)緩存原理
第一次發(fā)出一個(gè)查詢sql,sql查詢結(jié)果寫入SqlSession的一級(jí)緩存中茂契,緩存使用的數(shù)據(jù)結(jié)構(gòu)為(HashMap)蝶桶。
同一個(gè)SqlSession發(fā)出第二次查詢時(shí),就從緩存中獲取掉冶。如果兩次中間出現(xiàn)commit操作(update/insert/delete)真竖,則本SqlSession的一級(jí)緩存全部清空(為了緩存中記錄最新的數(shù)據(jù),避免臟讀)厌小,從數(shù)據(jù)庫查詢恢共。
- key:mapperID+offset+limit+Sql+所有的入?yún)?/strong>
- value:查詢結(jié)果
一級(jí)緩存的生命周期
- 開啟數(shù)據(jù)庫會(huì)話,創(chuàng)建新的SqlSession對(duì)象璧亚,SqlSession對(duì)象中會(huì)有一個(gè)Executor對(duì)象讨韭,Executor對(duì)象持有新的PerpetualCache對(duì)象;會(huì)話結(jié)束時(shí),SqlSession對(duì)象以及Executor對(duì)象和PerpetualCache對(duì)象一并銷毀透硝。
- SqlSession調(diào)用close()方法狰闪,會(huì)釋放掉一級(jí)緩存PerpetualCache對(duì)象,一級(jí)緩存不可用濒生。
- 如果SqlSession調(diào)用clearCache()方法埋泵,會(huì)清空PerpetualCache對(duì)象,但對(duì)象仍可用甜攀。
- SqlSession執(zhí)行任何一個(gè)insert()秋泄、update()琐馆、delete()操作,會(huì)清空PerpetualCache對(duì)象规阀,但對(duì)象仍可用。
一級(jí)緩存的工作流程
- 對(duì)于某個(gè)查詢瘦麸,根據(jù)statementId谁撼、params、rowBounds來構(gòu)建key值滋饲,根據(jù)key值去緩存Cache中查找結(jié)果厉碟;
- 判斷從Cache中根據(jù)特定的key值取的數(shù)據(jù)數(shù)據(jù)是否為空,即是否命中屠缭;
- 如果命中箍鼓,則直接返回查詢結(jié)果;
- 如果沒有命中:
- 數(shù)據(jù)庫中查詢結(jié)果呵曹;
- 將key和查詢結(jié)果分別作為key和value存入Cache緩存中款咖;
- 查詢結(jié)果返回。
- 結(jié)束奄喂。
一級(jí)緩存性能分析
- Session級(jí)別的一級(jí)緩存設(shè)計(jì)比較簡單铐殃,只使用了HashMap來維護(hù),并沒有對(duì)HashMap的容量和大小進(jìn)行限制跨新。
- SqlSession的生存時(shí)間很短富腊。使用一個(gè)SqlSession對(duì)象執(zhí)行的操作不會(huì)太多,執(zhí)行完就會(huì)消亡域帐;
- 對(duì)于某一個(gè)SqlSession對(duì)象而言赘被,只要執(zhí)行commit操作(update、insert肖揣、delete)民假,都會(huì)將這個(gè)SqlSession對(duì)象中對(duì)應(yīng)的一級(jí)緩存清空掉,所以一般情況下不會(huì)出現(xiàn)緩存過大许饿,影響JVM內(nèi)存空間的問題阳欲;
- 可以手動(dòng)地釋放掉SqlSession對(duì)象中的緩存。
- 一級(jí)緩存是粗粒度緩存,沒有更新緩存和緩存過期概念球化。
- 對(duì)于數(shù)據(jù)變化頻率很大秽晚,并且需要高時(shí)效準(zhǔn)確性的數(shù)據(jù)要求,我們使用SqlSession查詢的時(shí)候筒愚,要控制好SqlSession的生存時(shí)間赴蝇,SqlSession的生存時(shí)間越長,它其中緩存的數(shù)據(jù)有可能就越舊巢掺,從而造成和真實(shí)數(shù)據(jù)庫的誤差句伶;同時(shí)對(duì)于這種情況,用戶也可以手動(dòng)地適時(shí)清空SqlSession中的緩存陆淀;
- 對(duì)于只執(zhí)行考余、并且頻繁執(zhí)行大范圍的select操作的SqlSession對(duì)象,SqlSession對(duì)象的生存時(shí)間不應(yīng)過長轧苫。
二級(jí)緩存
二級(jí)緩存是mapper級(jí)別的楚堤,mapper以命名空間為單位創(chuàng)建緩存數(shù)據(jù)結(jié)構(gòu)(HashMap),二級(jí)緩存通過CachingExecutor(Executor的代理對(duì)象)實(shí)現(xiàn)。
二級(jí)緩存原理
所有查詢操作含懊,在CachingExecutor都會(huì)先匹配緩存中是否存在身冬,否則查詢數(shù)據(jù)庫。
- key:mapperID+offset+limit+Sql+所有的入?yún)?/strong>
- value:查詢結(jié)果
二級(jí)緩存工作模式
二級(jí)緩存機(jī)制關(guān)鍵在于Executor對(duì)象岔乔。若配置【cacheEnable=true】酥筝,則為SqlSession創(chuàng)建Executor加上一個(gè)裝飾者(CachingExecutor)。這時(shí)由CachingExecutor對(duì)象來完成操作請(qǐng)求雏门。
CachingExecutor對(duì)于查詢請(qǐng)求嘿歌,先判斷在Application級(jí)別的二級(jí)緩存是否有結(jié)果,如果有直接返回結(jié)果剿配。若沒有搅幅,再交給真正的Executor對(duì)象來完成查詢,之后CachingExecutor會(huì)將真正Executor返回的結(jié)果放置在緩存中呼胚,在返回給用戶茄唐。
二級(jí)緩存劃分
MyBatis并不簡單將Application就只有一個(gè)Cache緩存對(duì)象,它將緩存劃分的更新蝇更,即是mapper級(jí)別的(即每一個(gè)mapper一個(gè)緩存對(duì)象)沪编。
1. 為每一個(gè)mapper分配一個(gè)緩存對(duì)象(對(duì)于每一個(gè)mapper.xml,在其中使用<cache> 節(jié)點(diǎn))。
2. 多個(gè)mapper共用一個(gè)緩存對(duì)象(使用<cache-ref namespace="">節(jié)點(diǎn)年扩,來指定你的這個(gè)Mapper使用到了哪一個(gè)Mapper的Cache緩存)蚁廓。
二級(jí)緩存的開啟
MyBatis對(duì)二級(jí)緩存的支持粒度較細(xì),需要具體指定到某條查詢語句上厨幻。如果要開啟二級(jí)緩存相嵌,需做到如下三點(diǎn):
- MyBatis支持二級(jí)緩存的總開關(guān):全局配置變量參數(shù)【cacheEnabled=true】腿时。
- 該select語句所在的Mapper,配置了<cache> 或<cached-ref>節(jié)點(diǎn)饭宾,并且有效批糟。
- 該select語句的參數(shù) useCache=true。
二級(jí)緩存的實(shí)現(xiàn)
MyBatis 對(duì)于二級(jí)緩存的實(shí)現(xiàn)非常靈活看铆,自己內(nèi)部實(shí)現(xiàn)了Cache的一系列的實(shí)現(xiàn)類徽鼎,并提供了各種緩存刷新策略LRU、FIFO等弹惦。同時(shí)它也允許自定義Cache接口實(shí)現(xiàn)否淤,需實(shí)現(xiàn)org.apache.ibatis.cache.Cache接口,然后將Cache的實(shí)現(xiàn)類配置在<cache type="">節(jié)點(diǎn)的type屬性上棠隐。此外石抡,它也支持與第三方緩存庫如Memecached的集成。
二級(jí)緩存的實(shí)現(xiàn)有三種選擇:
-
MyBatis自身提供的緩存實(shí)現(xiàn)宵荒;
-
MyBatis定義了大量的Cache的裝飾器來增強(qiáng)Cache緩存的功能
-
對(duì)于每個(gè)Cache而言汁雷,都有容量限制净嘀,MyBatis提供了各種策略來對(duì)Cache緩存的容量進(jìn)行控制报咳,以及對(duì)于Cache中的數(shù)據(jù)進(jìn)行刷新和置換。主要有以下幾個(gè)刷新和置換策略:
LRU:Least Recently Used,最近最少使用算法挖藏,即緩存中容量滿了暑刃,會(huì)將緩存最近最少使用的數(shù)據(jù)清楚,添加上新的記錄膜眠。
FIFO:First In First Out,先進(jìn)先出算法岩臣,即緩存中容量滿了,會(huì)將最先進(jìn)來的數(shù)據(jù)清楚。
Scheduled:指定時(shí)間間隔清空算法宵膨,該算法會(huì)以指定的某一個(gè)時(shí)間間隔將Cache緩存中的數(shù)據(jù)清空架谎。
-
用戶自定義的Cache接口實(shí)現(xiàn);
跟第三方內(nèi)存緩存庫的集成辟躏;
二級(jí)緩存應(yīng)用場景
-
使用場景
對(duì)于訪問響應(yīng)速度要求高谷扣,但是實(shí)時(shí)性不高的查詢,可以采用二級(jí)緩存技術(shù)捎琐。 -
注意事項(xiàng)
在使用二級(jí)緩存的時(shí)候会涎,要設(shè)置一下刷新間隔(cache標(biāo)簽中有一個(gè)flashInterval屬性)來定時(shí)刷新二級(jí)緩存,這個(gè)刷新間隔根據(jù)具體需求來設(shè)置瑞凑,比如設(shè)置30分鐘末秃、60分鐘等,單位為毫秒籽御。
二級(jí)緩存局限性
Mybatis二級(jí)緩存對(duì)細(xì)粒度的數(shù)據(jù)級(jí)別的緩存實(shí)現(xiàn)不好练慕。
場景
對(duì)商品信息進(jìn)行緩存惰匙,由于商品信息查詢?cè)L問量大,但是要求用戶每次查詢都是最新的商品信息铃将,此時(shí)如果使用二級(jí)緩存徽曲,就無法實(shí)現(xiàn)當(dāng)一個(gè)商品發(fā)生變化只刷新該商品的緩存信息而不刷新其他商品緩存信息,因?yàn)槎?jí)緩存是mapper級(jí)別的麸塞,當(dāng)一個(gè)商品的信息發(fā)送更新秃臣,所有的商品信息緩存數(shù)據(jù)都會(huì)清空。解決方法
此類問題哪工,需要在業(yè)務(wù)層根據(jù)需要對(duì)數(shù)據(jù)有針對(duì)性的緩存奥此。
比如可以對(duì)經(jīng)常變化的 數(shù)據(jù)操作單獨(dú)放到另一個(gè)namespace的mapper中。