MyBatis中的一級緩存和二級緩存

參考互聯(lián)網(wǎng)后端架構(gòu)的文章

一級緩存

一級緩存是SqlSession級別的緩存甘凭。在操作數(shù)據(jù)庫時需要構(gòu)造sqlSession對象靶瘸,在對象中有一個數(shù)據(jù)結(jié)構(gòu)用于存儲緩存數(shù)據(jù)庸疾。不同的sqlSession之間的緩存數(shù)據(jù)區(qū)域是互相不影響的攻礼。也就是他只能作用在同一個sqlSession中忍宋,不同的sqlSession中的緩存是互相不能讀取的。
一級緩存的工作原理:

image.png

用戶發(fā)起查詢請求,查找某條數(shù)據(jù)湃缎,sqlSession先去緩存中查找犀填,是否有該數(shù)據(jù),如果有嗓违,讀染叛病;
如果沒有蹂季,從數(shù)據(jù)庫中查詢冕广,并將查詢到的數(shù)據(jù)放入一級緩存區(qū)域,供下次查找使用偿洁。
但sqlSession執(zhí)行commit撒汉,即增刪改操作時會清空緩存。這么做的目的是避免臟讀涕滋。
如果commit不清空緩存睬辐,會有以下場景:A查詢了某商品庫存為10件,并將10件庫存的數(shù)據(jù)存入緩存中宾肺,之后被客戶買走了10件溯饵,數(shù)據(jù)被delete了,但是下次查詢這件商品時锨用,并不從數(shù)據(jù)庫中查詢丰刊,而是從緩存中查詢,就會出現(xiàn)錯誤增拥。
既然有了一級緩存啄巧,那么為什么要提供二級緩存呢?
二級緩存是mapper級別的緩存掌栅,多個SqlSession去操作同一個Mapper的sql語句秩仆,多個SqlSession可以共用二級緩存,二級緩存是跨SqlSession的渣玲。二級緩存的作用范圍更大。
還有一個原因弟晚,實際開發(fā)中忘衍,MyBatis通常和Spring進行整合開發(fā)。Spring將事務放到Service中管理卿城,對于每一個service中的sqlsession是不同的枚钓,這是通過mybatis-spring中的org.mybatis.spring.mapper.MapperScannerConfigurer創(chuàng)建sqlsession自動注入到service中的。 每次查詢之后都要進行關閉sqlSession瑟押,關閉之后數(shù)據(jù)被清空搀捷。所以spring整合之后,如果沒有事務,一級緩存是沒有意義的嫩舟。

二級緩存

二級緩存原理:

image.png

二級緩存是mapper級別的緩存氢烘,多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession可以共用二級緩存家厌,二級緩存是跨SqlSession的播玖。
UserMapper有一個二級緩存區(qū)域(按namespace分),其它mapper也有自己的二級緩存區(qū)域(按namespace分)饭于。每一個namespace的mapper都有一個二級緩存區(qū)域蜀踏,兩個mapper的namespace如果相同,這兩個mapper執(zhí)行sql查詢到數(shù)據(jù)將存在相同的二級緩存區(qū)域中掰吕。

開啟二級緩存:

1果覆,打開總開關
在MyBatis的配置文件中加入:
[html] view plain copy print?
<span style="font-size:18px;"><settings>

<setting name="cacheEnabled" value="true"/>
</settings> </span>
2,在需要開啟二級緩存的mapper.xml中加入caceh標簽
[html] view plain copy print?
<span style="font-size:18px;"><cache/></span>
3殖熟,讓使用二級緩存的POJO類實現(xiàn)Serializable接口
[java] view plain copy print?
<span style="font-size:18px;">public class User implements Serializable {}</span>

測試一下
[java] view plain copy print?
<span style="font-size:18px;">@Test
public void testCache2() throws Exception {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
sqlSession1.close();
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}</span>
輸出結(jié)果:
[html] view plain copy print?
<span style="font-size:18px;">DEBUG [main] - Cache Hit Ratio [com.iot.mybatis.mapper.UserMapper]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 103887628.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - ==> Preparing: SELECT * FROM user WHERE id=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 1
User [id=1, username=張三, sex=1, birthday=null, address=null]
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@631330c]
DEBUG [main] - Returned connection 103887628 to pool.
DEBUG [main] - Cache Hit Ratio [com.iot.mybatis.mapper.UserMapper]: 0.5
User [id=1, username=張三, sex=1, birthday=null, address=null]</span>
我們可以從打印的信息看出局待,兩個sqlSession,去查詢同一條數(shù)據(jù)吗讶,只發(fā)起一次select查詢語句燎猛,第二次直接從Cache中讀取。

前面我們說到照皆,Spring和MyBatis整合時重绷, 每次查詢之后都要進行關閉sqlSession,關閉之后數(shù)據(jù)被清空膜毁。所以spring整合之后昭卓,如果沒有事務,一級緩存是沒有意義的瘟滨。那么如果開啟二級緩存候醒,關閉sqlsession后,會把該sqlsession一級緩存中的數(shù)據(jù)添加到namespace的二級緩存中杂瘸。這樣倒淫,緩存在sqlsession關閉之后依然存在。

總結(jié):

對于查詢多commit少且用戶對查詢結(jié)果實時性要求不高败玉,此時采用mybatis二級緩存技術(shù)降低數(shù)據(jù)庫訪問量敌土,提高訪問速度。

但不能濫用二級緩存运翼,二級緩存也有很多弊端返干,從MyBatis默認二級緩存是關閉的就可以看出來。
二級緩存是建立在同一個namespace下的血淌,如果對表的操作查詢可能有多個namespace矩欠,那么得到的數(shù)據(jù)就是錯誤的。
舉個簡單的例子:
訂單和訂單詳情,orderMapper癌淮、orderDetailMapper躺坟。在查詢訂單詳情時我們需要把訂單信息也查詢出來,那么這個訂單詳情的信息被二級緩存在orderDetailMapper的namespace中该默,這個時候有人要修改訂單的基本信息瞳氓,那就是在orderMapper的namespace下修改,他是不會影響到orderDetailMapper的緩存的栓袖,那么你再次查找訂單詳情時匣摘,拿到的是緩存的數(shù)據(jù),這個數(shù)據(jù)其實已經(jīng)是過時的裹刮。

根據(jù)以上音榜,想要使用二級緩存時需要想好兩個問題:
1)對該表的操作與查詢都在同一個namespace下,其他的namespace如果有操作捧弃,就會發(fā)生數(shù)據(jù)的臟讀赠叼。
2)對關聯(lián)表的查詢,關聯(lián)的所有表的操作都必須在同一個namespace违霞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嘴办,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子买鸽,更是在濱河造成了極大的恐慌涧郊,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件眼五,死亡現(xiàn)場離奇詭異妆艘,居然都是意外死亡,警方通過查閱死者的電腦和手機看幼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進店門批旺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人诵姜,你說我怎么就攤上這事汽煮。” “怎么了棚唆?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵暇赤,是天一觀的道長。 經(jīng)常有香客問我瑟俭,道長翎卓,這世上最難降的妖魔是什么契邀? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任摆寄,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘微饥。我一直安慰自己逗扒,他們只是感情好,可當我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布欠橘。 她就那樣靜靜地躺著矩肩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪肃续。 梳的紋絲不亂的頭發(fā)上黍檩,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天,我揣著相機與錄音始锚,去河邊找鬼刽酱。 笑死,一個胖子當著我的面吹牛瞧捌,可吹牛的內(nèi)容都是我干的棵里。 我是一名探鬼主播,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼姐呐,長吁一口氣:“原來是場噩夢啊……” “哼殿怜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起曙砂,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤头谜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后麦轰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乔夯,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年款侵,在試婚紗的時候發(fā)現(xiàn)自己被綠了末荐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡新锈,死狀恐怖甲脏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情妹笆,我是刑警寧澤块请,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站拳缠,受9級特大地震影響墩新,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜窟坐,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一海渊、第九天 我趴在偏房一處隱蔽的房頂上張望绵疲。 院中可真熱鬧,春花似錦臣疑、人聲如沸盔憨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽郁岩。三九已至,卻和暖如春缺狠,著一層夾襖步出監(jiān)牢的瞬間问慎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工挤茄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蝴乔,地道東北人。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓驮樊,卻偏偏與公主長得像薇正,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子囚衔,可洞房花燭夜當晚...
    茶點故事閱讀 45,781評論 2 361

推薦閱讀更多精彩內(nèi)容