MyBatis10-二級緩存

1. 二級緩存的原理

前面介紹了异袄,mybatis中的二級緩存是mapper級別的緩存,值得注意的是冤灾,不同的mapper都有一個二級緩存前域,也就是說,不同的mapper之間的二級緩存是互不影響的韵吨。為了更加清楚的描述二級緩存匿垄,先來看一個示意圖:



從圖中可以看出:

1.sqlSession1去查詢用戶id為1的用戶信息,查詢到用戶信息會將查詢數(shù)據(jù)存儲到該UserMapper的二級緩存中归粉。
2.如果SqlSession3去執(zhí)行相同 mapper下sql椿疗,執(zhí)行commit提交,則會清空該UserMapper下二級緩存區(qū)域的數(shù)據(jù)糠悼。
3.sqlSession2去查詢用戶id為1的用戶信息届榄,去緩存中找是否存在數(shù)據(jù),如果存在直接從緩存中取出數(shù)據(jù)倔喂。
緩存的執(zhí)行原理和前面提到的一級緩存是差不多的铝条,二級緩存與一級緩存區(qū)別在于二級緩存的范圍更大,多個sqlSession可以共享一個mapper中的二級緩存區(qū)域席噩。mybatis是如何區(qū)分不同mapper的二級緩存區(qū)域呢班缰?它是按照不同mapper有不同的namespace來區(qū)分的,也就是說悼枢,如果兩個mapper的namespace相同埠忘,即使是兩個mapper,那么這兩個mapper中執(zhí)行sql查詢到的數(shù)據(jù)也將存在相同的二級緩存區(qū)域中。

2. 二級緩存的使用

明白了mybatis中二級緩存的原理后莹妒,接下來就是如何使用二級緩存了假丧。在使用之前,首先得開啟二級緩存的開關(guān)动羽。

2.1 開啟二級緩存

由于mybaits的二級緩存是mapper范圍級別包帚,所以除了在SqlMapConfig.xml設(shè)置二級緩存的總開關(guān)外,還要在具體的mapper.xml中開啟二級緩存运吓。設(shè)置如下:



這是在SqlMapConfig.xml中設(shè)置的渴邦,還得在具體的mapper.xml中設(shè)置,如下:


可以看到拘哨,具體的mapper中僅僅就一個<cache>標(biāo)簽谋梭,并沒有配置啥東西,這是因為mybatis中有默認(rèn)的實現(xiàn)倦青,我們?nèi)绻慌渲梦痛玻敲淳湍J(rèn)使用那個默認(rèn)的實現(xiàn)。在mybatis的核心包里有cache的接口和這個默認(rèn)的實現(xiàn)产镐,我截個圖:


所以就明白了隘庄,為啥不用配置都可以使用,mybatis中也就只有這一個默認(rèn)實現(xiàn)類癣亚,如果不使用mybatis的默認(rèn)二級緩存的話丑掺,就需要自己實現(xiàn)cache接口,然后再在mapper.xml中配置一下了述雾,關(guān)于這個我在下面再談街州,現(xiàn)在先把二級緩存用起來!

將po類實現(xiàn)Serializable接口

開啟了二級緩存后玻孟,還需要將要緩存的pojo實現(xiàn)Serializable接口唆缴,為了將緩存數(shù)據(jù)取出執(zhí)行反序列化操作,因為二級緩存數(shù)據(jù)存儲介質(zhì)多種多樣黍翎,不一定只存在內(nèi)存中面徽,有可能存在硬盤中玩敏,如果我們要再取這個緩存的話斗忌,就需要反序列化了质礼。所以建議mybatis中的pojo都去實現(xiàn)Serializable接口眶蕉。下面以User為例截個圖:


2.3 測試mybatis的二級緩存

@Test
public void testCache2() throws Exception {
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    SqlSession sqlSession3 = sqlSessionFactory.openSession();
    // 創(chuàng)建代理對象
    UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
    // 第一次發(fā)起請求蚓让,查詢id為1的用戶
    User user1 = userMapper1.findUserById(1);
    System.out.println(user1);  
    //這里執(zhí)行關(guān)閉操作,將sqlsession中的數(shù)據(jù)寫到二級緩存區(qū)域
    sqlSession1.close();

    //sqlSession3用來清空緩存的锄列,如果要測試二級緩存,需要把該部分注釋掉
    //使用sqlSession3執(zhí)行commit()操作
    UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
    User user  = userMapper3.findUserById(1);
    user.setUsername("倪升武");
    userMapper3.updateUser(user);
    //執(zhí)行提交,清空UserMapper下邊的二級緩存
    sqlSession3.commit();
    sqlSession3.close();

    UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
    // 第二次發(fā)起請求歇万,查詢id為1的用戶
    User user2 = userMapper2.findUserById(1);
    System.out.println(user2);

    sqlSession2.close();

}

我們先把sqlSession3部分注釋掉來測試一下二級緩存的結(jié)果:

二級緩存
  當(dāng)我們把sqlSession3部分加上后,再測試一下二級緩存結(jié)果:
二級緩存2
  到這里拣技,就明白了mybatis中二級緩存的執(zhí)行原理了.

2.4 其他配置(useCache和flushCache)

mybatis中還可以配置userCache和flushCache等配置項泵三,userCache是用來設(shè)置是否禁用二級緩存的烫幕,在statement中設(shè)置useCache=false可以禁用當(dāng)前select語句的二級緩存冕末,即每次查詢都會發(fā)出sql去查詢,默認(rèn)情況是true嘹屯,即該sql使用二級緩存攻询。

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

這種情況是針對每次查詢都需要最新的數(shù)據(jù)sql,要設(shè)置成useCache=false抚垄,禁用二級緩存蜕窿,直接從數(shù)據(jù)庫中獲取谋逻。 在mapper的同一個namespace中呆馁,如果有其它insert桐经、update、delete操作數(shù)據(jù)后需要刷新緩存浙滤,如果不執(zhí)行刷新緩存會出現(xiàn)臟讀阴挣。 設(shè)置statement配置中的flushCache=”true” 屬性,默認(rèn)情況下為true纺腊,即刷新緩存畔咧,如果改成false則不會刷新。使用緩存時如果手動修改數(shù)據(jù)庫表中的查詢數(shù)據(jù)會出現(xiàn)臟讀揖膜。

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">

一般下執(zhí)行完commit操作都需要刷新緩存誓沸,flushCache=true表示刷新緩存,這樣可以避免數(shù)據(jù)庫臟讀壹粟。所以我們不用設(shè)置拜隧,默認(rèn)即可,這里只是提一下.

3. MyBatis整合ehcache分布式緩存框架

3.1 問題的由來

上面的部分主要總結(jié)了一下mybatis中二級緩存的使用趁仙,但是mybatis中默認(rèn)自帶的二級緩存有個弊端洪添,即無法實現(xiàn)分布式緩存,什么意思呢雀费?就是說緩存的數(shù)據(jù)在自己的服務(wù)器上干奢,假設(shè)現(xiàn)在有兩個服務(wù)器A和B,用戶訪問的時候訪問了A服務(wù)器盏袄,查詢后的緩存就會放在A服務(wù)器上忿峻,假設(shè)現(xiàn)在有個用戶訪問的是B服務(wù)器,那么他在B服務(wù)器上就無法獲取剛剛那個緩存辕羽,如下圖所示:
緩存弊端

  所以我們?yōu)榱私鉀Q這個問題炭菌,就得找一個分布式的緩存,專門用來存儲緩存數(shù)據(jù)的逛漫,這樣不同的服務(wù)器要緩存數(shù)據(jù)都往它那里存黑低,取緩存數(shù)據(jù)也從它那里取,如下圖所示:
分布式緩存
  這樣就能解決上面所說的問題酌毡,為了提高系統(tǒng)并發(fā)性能克握、我們一般對系統(tǒng)進行上面這種分布式部署(集群部署方式),所以要使用分布式緩存對緩存數(shù)據(jù)進行集中管理枷踏。但是mybatis無法實現(xiàn)分布式緩存菩暗,需要和其它分布式緩存框架進行整合,這里主要介紹ehcache旭蠕。

3.2 整合方法

上文一開始提到過停团,mybatis提供了一個cache接口旷坦,如果要實現(xiàn)自己的緩存邏輯,實現(xiàn)cache接口開發(fā)即可佑稠。mybatis本身默認(rèn)實現(xiàn)了一個秒梅,但是這個緩存的實現(xiàn)無法實現(xiàn)分布式緩存,所以我們要自己來實現(xiàn)舌胶。ehcache分布式緩存就可以捆蜀,mybatis提供了一個針對cache接口的ehcache實現(xiàn)類,這個類在mybatis和ehcache的整合包中幔嫂。所以首先我們需要導(dǎo)入整合包(點我下載)辆它。

jar包
  導(dǎo)入了jar包后,配置mapper中cache中的type為ehcache對cache接口的實現(xiàn)類型履恩。ehcache對cache接口有一個實現(xiàn)類為:
實現(xiàn)類
  我們將該類的完全限定名寫到type屬性中即可锰茉,如下:
配置
  OK,配置完成切心,現(xiàn)在mybatis就會自動去執(zhí)行這個ehcache實現(xiàn)類了飒筑,就不會使用自己默認(rèn)的二級緩存了,但是使用ehcache還有一個緩存配置別忘了昙衅,在classpath下新建一個ehcache.xml文件:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">

    <diskStore path="F:\develop\ehcache"/>

    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </defaultCache>
</ehcache>

4. 二級緩存的應(yīng)用場景和局限性

對于訪問多的查詢請求且用戶對查詢結(jié)果實時性要求不高扬霜,此時可采用mybatis二級緩存技術(shù)降低數(shù)據(jù)庫訪問量,提高訪問速度而涉,業(yè)務(wù)場景比如:耗時較高的統(tǒng)計分析sql著瓶、電話賬單查詢sql等。實現(xiàn)方法如下:通過設(shè)置刷新間隔時間啼县,由mybatis每隔一段時間自動清空緩存材原,根據(jù)數(shù)據(jù)變化頻率設(shè)置緩存刷新間隔flushInterval,比如設(shè)置為30分鐘季眷、60分鐘余蟹、24小時等,根據(jù)需求而定子刮。
  mybatis二級緩存對細粒度的數(shù)據(jù)級別的緩存實現(xiàn)不好威酒,比如如下需求:對商品信息進行緩存,由于商品信息查詢訪問量大挺峡,但是要求用戶每次都能查詢最新的商品信息葵孤,此時如果使用mybatis的二級緩存就無法實現(xiàn)當(dāng)一個商品變化時只刷新該商品的緩存信息而不刷新其它商品的信息,因為mybaits的二級緩存區(qū)域以mapper為單位劃分的橱赠,當(dāng)一個商品信息變化會將所有商品信息的緩存數(shù)據(jù)全部清空尤仍。解決此類問題可能需要在業(yè)務(wù)層根據(jù)需求對數(shù)據(jù)有針對性緩存。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末狭姨,一起剝皮案震驚了整個濱河市宰啦,隨后出現(xiàn)的幾起案子苏遥,更是在濱河造成了極大的恐慌,老刑警劉巖赡模,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件田炭,死亡現(xiàn)場離奇詭異,居然都是意外死亡纺裁,警方通過查閱死者的電腦和手機诫肠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門司澎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來欺缘,“玉大人,你說我怎么就攤上這事挤安⊙枋猓” “怎么了?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵蛤铜,是天一觀的道長嫩絮。 經(jīng)常有香客問我,道長围肥,這世上最難降的妖魔是什么剿干? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮穆刻,結(jié)果婚禮上置尔,老公的妹妹穿的比我還像新娘。我一直安慰自己氢伟,他們只是感情好榜轿,可當(dāng)我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著朵锣,像睡著了一般谬盐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上诚些,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天飞傀,我揣著相機與錄音,去河邊找鬼诬烹。 笑死砸烦,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的椅您。 我是一名探鬼主播外冀,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼掀泳!你這毒婦竟也來了雪隧?” 一聲冷哼從身側(cè)響起西轩,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎脑沿,沒想到半個月后藕畔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡庄拇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年注服,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片措近。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡溶弟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瞭郑,到底是詐尸還是另有隱情辜御,我是刑警寧澤,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布屈张,位于F島的核電站擒权,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏阁谆。R本人自食惡果不足惜碳抄,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望场绿。 院中可真熱鬧剖效,春花似錦、人聲如沸裳凸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姨谷。三九已至逗宁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間梦湘,已是汗流浹背瞎颗。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留捌议,地道東北人哼拔。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像瓣颅,于是被迫代替她去往敵國和親倦逐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,562評論 2 349

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