mybatis----緩存

查詢緩存

mybaits提供了一級緩存和二級緩存,用于減輕數據壓力,提高數據庫性能。。

1.1 什么是一級緩存

我們創建出一個SqlSession對象表示一次數據庫會話,在這次會話中,我們有可能好幾次執行一樣的查詢語句,若是每次都去訪問數據庫,那么就會造成數據庫資源的浪費,所以mybatis引入一級緩存,在SqlSession中建立一個緩存(數據結構為hashmap),每次查詢先去查看緩存中是否有,有的話就把結果返回,沒有的話再去查詢數據庫并將查到的結果緩存起來。

需要注意的是,不同的sqlSession對象之間的緩存數據區域是互相不影響的。

SqlSession只是對外的接口,真正執行各種數據庫操作的是Executor執行器(也是一個接口)。當創建了一個SqlSession對象時,MyBatis會為這個SqlSession對象創建一個新的Executor執行器,而緩存信息就被維護在這個Executor執行器中。MyBatis將緩存和對緩存相關的操作封裝成了Cache接口中。
SqlSession、Executor、Cache之間的關系如下列類圖所示:


sqlSession級別的一級緩存實際上就是使用PerpetualCache維護的。

1.2一級緩存的生命周期

  1. 開啟一個數據庫會話時,會創建一個新的SqlSession對象,SqlSession對象中會有一個新的Executor對象,Executor對象中持有一個新的PerpetualCache對象;當會話結束時,SqlSession對象及其內部的Executor對象還有PerpetualCache對象也一并釋放掉;

  2. 如果SqlSession調用了close()方法,會釋放掉一級緩存PerpetualCache對象,此時一級緩存不可用;

  3. 如果SqlSession調用了clearCache(),會清空PerpetualCache對象中的數據,但是PerpetualCache對象仍可使用;

4.SqlSession中執行了一個更新增加刪除操作 ,都會清空全部PerpetualCache對象的數據,但是該對象可以繼續使用;

1.3 一級緩存的工作流程

  1. 對于某個查詢,根據statementId,params,rowBounds來構建一個key值;

  2. 根據這個key值去緩存Cache中判斷是否命中緩存;

  3. 如果命中,則直接將緩存結果返回;

  4. 如果沒命中:

     4.1  去數據庫中查詢數據,得到查詢結果;
    
     4.2  將key和查詢到的結果分別作為key,value對存儲到Cache中;
    
     4.3. 將查詢結果返回;
    
  5. 結束。

1.4 如何判斷兩次查詢是一樣的

從實現來看,mybatis是利用key是否相同來判斷兩次查詢是否相同的,而key是由statementId,params,rowBounds這三項構建的。

其中,statementId決定帶參數的sql(有“?”占位符的的sql或是需要拼接字符串的sql語句),params決定占位符傳入的參數或是要拼接的字符串,rowBounds決定查詢的結果集的范圍(也就是 limit x,y ),這三個參數決定了最終的sql,也就是說當這個最終的sql一樣時,那么就判斷這兩次是一樣查詢。

1.5 真正應用

真正開發的時候,sqlSession是用spring管理的,而mapper是在service里面調用,在這種情況下,什么時候會用到一級緩存呢?
實際上,在一個service里,只有一個sqlSession,在service結束之后才會關閉這個sqlSession,sqlSession關閉則緩存清空。所以一個service函數里面多次調用mapper是會走一級緩存的,而多次調用service則互不影響。


2.1 什么是二級緩存

二級緩存是namespace級別的緩存,多個SqlSession可以共用二級緩存,不同sqlSession操作同一個namespace下的同一個sql,就會走二級緩存。


二級緩存工作流程

2.2開啟二級緩存

在SqlMapConfig.xml里開啟mybatis的全局二級緩存開關,默認是開啟的:

<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>

還需要在要二級緩存開啟的mapper.xml里面開啟開關:
<cache/>

2.3 二級緩存與一級緩存區別

二級緩存與一級緩存區別,二級緩存的范圍更大,多個sqlSession可以共享一個namespace下的二級緩存區域。

2.4 測試二級緩存

需要關閉sqlSession1才會把內容寫到緩存,sqlSession2才會讀到:


在sqlSession1和sqlSession2之間加入以下代碼,為了測試更新操作是否清空緩存:


2.5 二級緩存參數設置

設置某些sql禁用二級緩存

在statement中設置useCache=false可以禁用當前select語句使用二級緩存,即每次查詢都會發出sql去查詢數據庫。默認情況是true,即該sql使用二級緩存。

<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

只有每次查詢都需要最新的數據sql,要設置成useCache=false,才禁用二級緩存。

刷新緩存操作

刷新就是清空緩存,在insert update delete等statement中設置flushCache="true"(默認就是true),進行這些操作后會清空緩存,可以避免臟讀的情況。

刷新間隔參數

默認是沒有刷新間隔,刷新只在調用語句時刷新(這里的刷新都是指清空)

引用數目屬性

size:可被設置成任意正整數,默認值是1024

readOnly屬性

可被設置成true或是false,默認是false。只讀為true的緩存的對象實例是同一個;只讀為false的緩存返回的對象實例是拷貝的(通過序列化,所以配置成false需要pojo實現序列化接口),慢但是安全。

一個設置參數的例子

<cache eviction="FIFO" flushInterval="60 000" size="512" readOnly="true"/>
這個配置了一個FIFO緩存;并每隔60秒(60 000ms)刷新;存儲結果對象或結果列表的引用數是512個;返回的結果是只讀的,因此在不同線程中調用修改它們會沖突。可用的回收策略默認是LRU。

2.6 二級緩存應用場景

單表查詢時,對于實時性要求不高的請求,可以采用二級緩存并設置緩存刷新間隔來減少數據庫訪問量,提高訪問速度。

2.7 mybatis二級緩存局限性

最致命的是,多表查詢的情況出現的問題,比如我做訂單和用戶的多表查詢,這個statement可以寫在UserMapper.xml或是OrderMapper.xml或者是另創一個xml,假設我把這個statement放進OrderMapper.xml,我多表查詢了一次,結果被緩存下來,那么這時候我再去修改user的信息,可是這個更新操作是UserMapper.xml,我們使用mybatis的逆向工程,這兩個xml的namespace是不一樣的,也就是說這次更新操作沒有清空OrderMapper的緩存,那么我下次多表查詢就是查到錯誤的數據。
解決方法:
可以加入<cache-ref namespace="mapper.StudentMapper"/>配置,cache-ref代表引用別的命名空間的Cache配置,兩個命名空間的操作使用的是同一個Cache。

也可以是設計一個攔截器,判斷涉及到的表,進行更新操作,把有關的表的緩存都清空,不過這樣效率有點低。

mybatis的二級緩存默認是本地的,分布式環境下可能會有過時緩存數據被讀取的情況,所以還是放棄mybatis的二級緩存,選擇在業務層引入可控制的緩存替代比較好,比如redis等等。

3. ehcache

ehcache可以對頁面、對象、數據進行緩存,同時支持集群/分布式緩存。

怎么整合mybatis
  1. 在核心配置文件SqlMapConfig.xml開啟mybatis的二級緩存,默認是開啟的

  2. 導入ehcache相關jar包

  • ehcache-core-2.6.5.jar
  • mybatis-ehcache-1.0.2.jar
  1. 在classpath下加入ehcache.xml文件


  2. 在XXXMapper.xml中開啟二緩存,XXXMapper.xml下的sql執行完成會存儲到它的緩存區域(HashMap)


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容