緩存技術(shù)是一種“以空間換時間”的設(shè)計理念衣摩,是利用內(nèi)存空間資源來提高數(shù)據(jù)檢索速度的有效手段之一孕索。Mybatis包含一個非常強大的查詢緩存特性甩牺,可以非常方便地配置和定制嘲碱。MyBatis將數(shù)據(jù)緩存設(shè)計成兩級結(jié)構(gòu),分為一級緩存址否、二級緩存吁峻,如下圖所示:
一級緩存
1. 一級緩存簡介
??一級緩存基于PrepetualCache的HashMap本地緩存,其存儲作用域為Session在张,位于表示一次數(shù)據(jù)庫會話的SqlSession對象之中用含。
??每當我們使用MyBatis開啟一次和數(shù)據(jù)庫的會話,MyBatis會創(chuàng)建出一個SqlSession對象表示一次數(shù)據(jù)庫會話帮匾。在對數(shù)據(jù)庫的一次會話中啄骇,我們有可能會反復地執(zhí)行完全相同的查詢語句,如果不采取一些措施的話瘟斜,每一次查詢都會查詢一次數(shù)據(jù)庫缸夹,而我們在極短的時間內(nèi)做了完全相同的查詢,那么它們的結(jié)果極有可能完全相同螺句,由于查詢一次數(shù)據(jù)庫的代價很大虽惭,這有可能造成很大的資源浪費。
??為了解決這一問題蛇尚,減少資源的浪費芽唇,MyBatis會在表示會話的SqlSession對象中建立一個簡單的緩存,將每次查詢到的結(jié)果結(jié)果緩存起來取劫,當下次查詢的時候匆笤,如果判斷先前有個完全一樣的查詢,會直接從緩存中直接將結(jié)果取出谱邪,返回給用戶炮捧,不需要再進行一次數(shù)據(jù)庫查詢了。
??一級緩存是MyBatis內(nèi)部實現(xiàn)的一個特性惦银,用戶不能配置咆课,默認情況下自動支持的緩存,用戶沒有定制它的權(quán)利(不過這也不是絕對的扯俱,可以通過開發(fā)插件對它進行修改)书蚪。
2. 一級緩存實現(xiàn)
??實際上, MyBatis只是一個MyBatis對外的接口,SqlSession將它的工作交給了Executor執(zhí)行器這個角色來完成蘸吓,負責完成對數(shù)據(jù)庫的各種操作善炫。當創(chuàng)建了一個SqlSession對象時,MyBatis會為這個SqlSession對象創(chuàng)建一個新的Executor執(zhí)行器库继,而緩存信息就被維護在這個Executor執(zhí)行器中箩艺,MyBatis將緩存和對緩存相關(guān)的操作封裝成了Cache接口中。
??Executor接口的實現(xiàn)類BaseExecutor中擁有一個Cache接口的實現(xiàn)類PerpetualCache宪萄,則對于BaseExecutor對象而言艺谆,它將使用PerpetualCache對象維護緩存。
??綜上拜英,SqlSession對象静汤、Executor對象、Cache對象之間的關(guān)系如下圖所示:
3. 一級緩存的生命周期
a. MyBatis在開啟一個數(shù)據(jù)庫會話時,會創(chuàng)建一個新的SqlSession對象虫给,SqlSession對象中會有一個新的Executor對象藤抡,Executor對象中持有一個新的PerpetualCache對象;當會話結(jié)束時抹估,SqlSession對象及其內(nèi)部的Executor對象還有PerpetualCache對象也一并釋放掉缠黍。
b. 如果SqlSession調(diào)用了close()方法,會釋放掉一級緩存PerpetualCache對象药蜻,一級緩存將不可用瓷式;
c. 如果SqlSession調(diào)用了clearCache(),會清空PerpetualCache對象中的數(shù)據(jù)语泽,但是該對象仍可使用贸典;
d. SqlSession中執(zhí)行了任何一個update操作(update()、delete()踱卵、insert()) 廊驼,都會清空PerpetualCache對象的數(shù)據(jù),但是該對象可以繼續(xù)使用颊埃;
4. 一級緩存的性能分析
??Cache最核心的實現(xiàn)其實就是一個Map蔬充,將本次查詢使用的特征值作為key,將查詢結(jié)果作為value存儲到Map中班利。所以MyBatis的一級緩存就是使用了簡單的HashMap饥漫,MyBatis只負責將查詢數(shù)據(jù)庫的結(jié)果存儲到緩存中去, 不會去判斷緩存存放的時間是否過長罗标、是否過期庸队,因此也就沒有對緩存的結(jié)果進行更新這一說了。
??此外闯割,Mybatis并沒有對HashMap的容量和大小進行限制彻消,有可能導致OutOfMemoryError錯誤。但是MyBatis這樣設(shè)計也有它自己的理由:
**a. ** 一般而言SqlSession的生存時間很短宙拉。一般情況下使用一個SqlSession對象執(zhí)行的操作不會太多宾尚,執(zhí)行完就會消亡;
**b. ** 對于某一個SqlSession對象而言谢澈,只要執(zhí)行update操作(update煌贴、insert、delete)锥忿,都會將這個SqlSession對象中對應的一級緩存清空掉牛郑,所以一般情況下不會出現(xiàn)緩存過大,影響JVM內(nèi)存空間的問題敬鬓;
**c. **可以手動地釋放掉SqlSession對象中的緩存淹朋。
二級緩存
1. MyBatis二級緩存的介紹和劃分
??二級緩存和一級緩存的機制相同笙各,默認也是采用PrepetualCache、HashMap存儲础芍,但是二級緩存是Application應用級別的緩存杈抢,它的是生命周期很長,跟Application的聲明周期一樣者甲,也就是說它的作用范圍是整個Application應用春感。但是MyBatis并不是簡單地對整個Application就只有一個Cache緩存對象,它將緩存劃分的更細虏缸,即是Mapper(nameSpace)級別的,即每一個Mapper都可以擁有一個Cache對象嫩实,具體如下:
a.為每一個Mapper分配一個Cache緩存對象(使用<cache>節(jié)點配置)
??MyBatis將Application級別的二級緩存細分到Mapper級別刽辙,即對于每一個Mapper.xml,如果在其中使用了<cache> 節(jié)點甲献,則MyBatis會為這個Mapper創(chuàng)建一個Cache緩存對象宰缤,如下圖所示:
注: 上述的每一個Cache對象,都會有一個自己所屬的namespace命名空間晃洒,并且會將Mapper的 namespace作為它們的ID慨灭。
b.多個Mapper共用一個Cache緩存對象(使用<cache-ref>節(jié)點配置)
??如果你想讓多個Mapper公用一個Cache的話,你可以使用<cache-ref namespace="">節(jié)點球及,來指定你的這個Mapper使用到了哪一個Mapper的Cache緩存氧骤。
在同一個namespace下的mapper文件中,執(zhí)行相同的查詢SQL吃引,第一次會去查詢數(shù)據(jù)庫筹陵,并寫到緩存中;第二次直接從緩存中取镊尺。當執(zhí)行SQL時兩次查詢中間發(fā)生了增刪改操作朦佩,則二級緩存清空。
2. 二級緩存的工作模式
??如上所言庐氮,一個SqlSession對象會使用一個Executor對象來完成會話操作语稠,MyBatis的二級緩存機制的關(guān)鍵就是對這個Executor對象做文章。如果用戶配置了"cacheEnabled=true"弄砍,那么MyBatis在為SqlSession對象創(chuàng)建Executor對象時仙畦,會對Executor對象加上一個裝飾者:CachingExecutor,這時SqlSession使用CachingExecutor對象來完成操作請求输枯。CachingExecutor對于查詢請求议泵,會先判斷該查詢請求在Application級別的二級緩存中是否有緩存結(jié)果,如果有查詢結(jié)果桃熄,則直接返回緩存結(jié)果先口;如果緩存中沒有型奥,再交給真正的Executor對象來完成查詢操作,之后CachingExecutor會將真正Executor返回的查詢結(jié)果放置到緩存中碉京,然后在返回給用戶厢汹。
3. 使用二級緩存,必須要具備的條件
??MyBatis對二級緩存的支持粒度很細谐宙,它會指定某一條查詢語句是否使用二級緩存烫葬。
??雖然在Mapper中配置了<cache>,并且為此Mapper分配了Cache對象,這并不表示我們使用Mapper中定義的查詢語句查到的結(jié)果都會放置到Cache對象之中凡蜻,我們必須指定Mapper中的某條選擇語句是否支持緩存搭综,即如下所示,在<select>節(jié)點中配置useCache="true"划栓,Mapper才會對此Select的查詢支持緩存特性兑巾,否則,不會對此select查詢忠荞,不會經(jīng)過Cache緩存蒋歌。如下所示,select語句配置了useCache="true"委煤,則表明這條select語句的查詢會使用二級緩存堂油。
<select id="selectByMinSalary" resultMap="BaseResultMap" parameterType="java.util.Map" useCache="true">
總之,要想使某條Select查詢支持二級緩存碧绞,你需要保證:
- MyBatis支持二級緩存的總開關(guān):全局配置(mybatis-config.xml)變量參數(shù) cacheEnabled=true府框。
-
該select語句所在的Mapper,配置了<cache> 或<cached-ref>節(jié)點头遭,并且有效寓免。
- 該select語句的參數(shù) useCache=true。
-
Pojo類必須實現(xiàn)序列化接口计维。
4. 刷新緩存
??在mapper的同一個namespace中袜香,如果有其他insert、update鲫惶、delete操作數(shù)據(jù)后需要刷新緩存蜈首,如果不執(zhí)行刷新緩存會出現(xiàn)臟讀。
??設(shè)置statement配置中的flushCache="true"屬性欠母,默認情況下為true即刷新緩存欢策,如果改成false則不會刷新緩存。
5. 二級緩存實現(xiàn)的選擇
??MyBatis對二級緩存的設(shè)計非常靈活赏淌,它自己內(nèi)部實現(xiàn)了一系列的Cache緩存實現(xiàn)類踩寇,并提供了各種緩存刷新策略如LRU,F(xiàn)IFO等等六水;另外俺孙,MyBatis還允許用戶自定義Cache接口實現(xiàn)辣卒,用戶是需要實現(xiàn)org.apache.ibatis.cache.Cache接口,然后將Cache實現(xiàn)類配置在<cache type="">節(jié)點的type屬性上即可睛榄;除此之外荣茫,MyBatis還支持跟第三方內(nèi)存緩存庫如Ehcache的集成。
MyBatis自身提供的二級緩存的實現(xiàn)
??MyBatis自身提供了豐富的场靴,并且功能強大的二級緩存的實現(xiàn)啡莉,它擁有一系列的Cache接口裝飾者,可以滿足各種對緩存操作和更新的策略旨剥。 對于每個Cache而言咧欣,都有一個容量限制,MyBatis各供了各種策略來對Cache緩存的容量進行控制泞边,以及對Cache中的數(shù)據(jù)進行刷新和置換该押。如下類圖所示:
6. Mybatis整合第三方緩存框架
- 我們系統(tǒng)為了提高系統(tǒng)并發(fā)性能,一般對系統(tǒng)進行分布式部署(集群部署方式)阵谚。
- 不使用分布式緩存,緩存的數(shù)據(jù)在各個服務(wù)單獨存儲烟具,不方便系統(tǒng)開發(fā)梢什,所以要使用分布式緩存對緩存數(shù)據(jù)進行集中管理。
- 第三方緩存框架一般有ehcache朝聋、memcache嗡午、redis緩存框架。