一:mybatis 介紹cache和使用cache
mybatis自帶的緩存構(gòu)架愚争,方便配置、功能強(qiáng)大捅彻、定制方便步淹。默認(rèn)情況下cache是沒(méi)有被開啟的缭裆。想要開啟此功能需要在sql映射文件中添加這樣一行:
<cache />
添加這一行后,會(huì)產(chǎn)生如下效果:
- 映射語(yǔ)句文件中的所有select 語(yǔ)句將會(huì)被緩存韧衣。
- 映射語(yǔ)句文件中的所有insert,update 和delete 語(yǔ)句會(huì)刷新緩存畅铭。
- 緩存會(huì)使用Least Recently Used(LRU,最近最少使用的)算法來(lái)收回勃蜘。
- 根據(jù)時(shí)間表(比如no Flush Interval,沒(méi)有刷新間隔), 緩存不會(huì)以任何時(shí)間順序來(lái)刷新炉擅。
- 緩存會(huì)存儲(chǔ)列表集合或?qū)ο?無(wú)論查詢方法返回什么)的1024 個(gè)引用谍失。
- 緩存會(huì)被視為是read/write(可讀/可寫)的緩存,意味著對(duì)象檢索不是共享的,而且可以安全地被調(diào)用者修改,而不干擾其他調(diào)用者或線程所做的潛在修改莹汤。
以上所有的屬性都可以通過(guò)<cache />
元素來(lái)修改:
<cache
eviction="FIFO"http://回收策略
flushInterval="60000"http://刷新間隔
size="512"http://引用數(shù)目
readOnly="true"http://只讀
/>
以上表明首先創(chuàng)建了一個(gè)先進(jìn)先出策略的緩存,并每隔 60 秒刷新,存數(shù)結(jié)果對(duì)象或列表的 512 個(gè)引用,而且返回的對(duì)象被認(rèn)為是只讀的,因此在不同線程中的調(diào)用者之間修改它們會(huì)導(dǎo)致沖突快鱼。
可用的收回策略有:
- LRU – 最近最少使用的:移除最長(zhǎng)時(shí)間不被使用的對(duì)象。
- FIFO – 先進(jìn)先出:按對(duì)象進(jìn)入緩存的順序來(lái)移除它們纲岭。
- SOFT – 軟引用:移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對(duì)象抹竹。
- WEAK – 弱引用:更積極地移除基于垃圾收集器狀態(tài)和弱引用規(guī)則的對(duì)象。
默認(rèn)的是LRU止潮。
屬性flushInterval(刷新間隔)可以被設(shè)置為任意的正整數(shù),而且它們代表一個(gè)合理的毫秒形式的時(shí)間段窃判。默認(rèn)情況是不設(shè)置,也就是沒(méi)有刷新間隔,緩存僅僅調(diào)用語(yǔ)句時(shí)刷新。
屬性size(引用數(shù)目)可以被設(shè)置為任意正整數(shù),要記住你緩存的對(duì)象數(shù)目和你運(yùn)行環(huán)境的可用內(nèi)存資源數(shù)目喇闸。默認(rèn)值是1024袄琳。
屬性readOnly(只讀)屬性可以被設(shè)置為true 或 false雳殊。只讀的緩存會(huì)給所有調(diào)用者返回緩存對(duì)象的相同實(shí)例痢艺。因此這些對(duì)象不能被修改。這提供了很重要的性能優(yōu)勢(shì)箕戳〗檠溃可讀寫的緩存會(huì)返回緩存對(duì)象的拷貝(通過(guò)序列化) 。這會(huì)慢一些,但是安全,因此默認(rèn)是false。
在<select />
標(biāo)簽中關(guān)于緩存的使用
屬性
flushCache:將其設(shè)置為 true,任何時(shí)候只要語(yǔ)句被調(diào)用,都會(huì)導(dǎo)致本地緩存和二級(jí)緩存都會(huì)被清空粱哼,默認(rèn)值:false。
useCache:將其設(shè)置為 true,將會(huì)導(dǎo)致本條語(yǔ)句的結(jié)果被二級(jí)緩存,默認(rèn)值:對(duì) select 元素為 true。如果設(shè)置為false盈蛮,那么即使啟用了<cache />
該條select的結(jié)構(gòu)也不會(huì)被二級(jí)緩存寸五。
二:下面結(jié)合springMVC+mybatis+mysql實(shí)際檢驗(yàn)
![數(shù)據(jù)表(user)](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/user%E8%A1%A8.png?raw=true)
模擬正常情況:
![返回結(jié)果](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/s1.png?raw=true)
- console輸出:
1.對(duì)比已有緩存的命中是0.0,所以從數(shù)據(jù)庫(kù)中fetch數(shù)據(jù),產(chǎn)生一次數(shù)據(jù)庫(kù)查詢。
![第一次請(qǐng)求的console顯示](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/1.png?raw=true)
2.緊接著第二次請(qǐng)求,從緩存中對(duì)比,比率是0.5憨琳,達(dá)到mybatis設(shè)定的范圍问拘,返回緩存數(shù)據(jù),沒(méi)有產(chǎn)生數(shù)據(jù)庫(kù)查詢。
![第二次請(qǐng)求的console顯示](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/2.png?raw=true)
3.過(guò)了60秒后請(qǐng)求辖佣,從緩存中對(duì)比世蔗,比率是0.33333333,沒(méi)有達(dá)到mybatis設(shè)定的范圍赁豆,從數(shù)據(jù)庫(kù)中fetch數(shù)據(jù),產(chǎn)生一次數(shù)據(jù)庫(kù)查詢甲抖。如果從cache標(biāo)簽中去掉flushInterval屬性,該查詢結(jié)果將始終走緩存,只當(dāng)在項(xiàng)目中發(fā)送delete哲戚、update脆炎、insert操作時(shí)才會(huì)更新緩存几蜻。
![第三次請(qǐng)求的console顯示](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/3.png?raw=true)
非正常情況:
- 輸入資源請(qǐng)求地址:
http://localhost:8080/springTest/UsersRest/getUsers?username=經(jīng)紀(jì)人1
![返回結(jié)果](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/s2.png?raw=true)
1.第一次請(qǐng)求正常輸出=>手動(dòng)從數(shù)據(jù)庫(kù)刪除數(shù)據(jù)粱栖、從另一個(gè)項(xiàng)目更改數(shù)據(jù)=>第二次查詢=>返回結(jié)果 手動(dòng)刪除:DELETE FROM user WHERE username = '經(jīng)紀(jì)人1'
![刪除后的數(shù)據(jù)結(jié)果](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/4.png?raw=true)
2.第二次請(qǐng)求后輸出結(jié)果
![手動(dòng)刪除數(shù)據(jù)庫(kù)后价认,返回的結(jié)果](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/s3.png?raw=true)
- console輸出:
![非正常情況下碎乃,查詢后console的顯示](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/5.png?raw=true)
這樣就出現(xiàn)了臟數(shù)據(jù)证九!
三:mybatis緩存使用注意事項(xiàng)
如果數(shù)據(jù)緩存在本地拥坛,另一個(gè)系統(tǒng)修改數(shù)據(jù)庫(kù)或者手動(dòng)修改數(shù)據(jù)庫(kù)時(shí)谍咆,會(huì)出現(xiàn)臟數(shù)據(jù)問(wèn)題。
一級(jí)緩存
Myatis的一級(jí)緩存默認(rèn)為SESSION,底層用PerpetualCache,里面使用map做為存儲(chǔ),并沒(méi)有做太多條件限制罩阵。二級(jí)緩存
MyBatis雖然全局配置開啟緩存喧笔,但是還是取決于是否使用了<cache/>
標(biāo)簽割按,如果使用了二級(jí)緩存膨报,需要注意:
每個(gè)<cache />
代表一個(gè)單獨(dú)的二級(jí)緩存,如果多個(gè)Mapper需要共享同一個(gè)二級(jí)緩存适荣,就需要使用<cache-ref/>
如果一個(gè)Mapper中查詢數(shù)據(jù)時(shí)丙躏,使用了多表聯(lián)查,當(dāng)另一個(gè)Mapper更新相關(guān)數(shù)據(jù)時(shí)束凑,如果沒(méi)有共享一個(gè)Cache,那么下一次該Mapper查詢時(shí)栅盲,就會(huì)出現(xiàn)讀到臟數(shù)據(jù)汪诉。使用二級(jí)緩存一般基于以下原則:
不經(jīng)常變動(dòng)的數(shù)據(jù),但經(jīng)常會(huì)使用
數(shù)據(jù)量比較大,系統(tǒng)多處會(huì)用到扒寄∮愎模或者跨系統(tǒng)用。
對(duì)性能有特別要求的地方该编。
濫用二級(jí)緩存迄本,有可能反而會(huì)降低性能,特別是根據(jù)條件查詢緩存课竣。
四:源碼淺析
![mybatis下關(guān)于cache的所有類](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/6.png?raw=true)
- 包內(nèi)容淺析
cache包下嘉赎,分為裝飾者包(其中有些關(guān)于cache的具體類文件,比如阻塞加鎖cache的委派于樟、fifo的cache委派公条,使用裝飾者模式起到了在不同使用場(chǎng)景靈活委派功能的目的,具有良好的擴(kuò)展性)和cache底層實(shí)現(xiàn)包迂曲,以上類都實(shí)現(xiàn)了Cache接口靶橱。 - 調(diào)用順序:
mybatis的關(guān)于cache有個(gè)CacheBuilder類,該類使用建造者模式路捧,在其中有個(gè)public Cache build()方法負(fù)責(zé)具體的<cache />
屬性的組裝关霸。通過(guò)MapperBuilderAssistant類調(diào)用CacheBuilder進(jìn)行具體的裝配順序操作。
![CacheBuilder類](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/c1.png?raw=true)
![CacheBuilder類](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/c2.png?raw=true)
![MapperBuilderAssistant類](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/c3.png?raw=true)
![MapperAnnotationBuilder類(負(fù)責(zé)處理mybatis的注解)](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/c4.png?raw=true)
![XMLMapperBuilder類(負(fù)責(zé)處理mybatismapper的xml)](https://github.com/sundayha/imageForBlog/blob/master/mybatis%20cache/c5.png?raw=true)
五:mybatis2級(jí)緩存機(jī)制杰扫、涉及的設(shè)計(jì)模式
百字不如一圖
裝飾者模式
裝飾者模式在不必改變?cè)愇募褪褂美^承的情況下队寇,動(dòng)態(tài)地?cái)U(kuò)展一個(gè)對(duì)象的功能。它是通過(guò)創(chuàng)建一個(gè)包裝類的對(duì)象涉波,也就是裝飾來(lái)包裹真實(shí)的對(duì)象英上。
- 執(zhí)行main()方法
public class Go {
public static void main(String[] args) {
System.out.println("套餐菜單\n");
EggsNoodles eggsNoodles = new EggsNoodles();
eggsNoodles.noodNameAndPrice();
DecoratorNoodles decoratorNoodles = new BeefNoodles(eggsNoodles);
decoratorNoodles.noodNameAndPrice();
DecoratorNoodles decoratorNoodles1 = new AubergineNoodles(eggsNoodles);
decoratorNoodles1.noodNameAndPrice();
DecoratorNoodles decoratorNoodles2 = new AubergineNoodles(decoratorNoodles);
decoratorNoodles2.noodNameAndPrice();
}
}
六:mybatis cache作用
mybatis cache 提供查詢緩存,用于減輕數(shù)據(jù)庫(kù)壓力啤覆,提高數(shù)據(jù)庫(kù)性能苍日。快速響應(yīng)用戶請(qǐng)求窗声,改善用戶體驗(yàn)相恃。適用于各種頻繁查詢數(shù)據(jù)且查詢條件不是十分復(fù)雜的業(yè)務(wù)。
需要源碼請(qǐng)留下郵箱
參考官方文檔:
http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#Auto-mapping