MyBatis緩存

一級(jí)緩存

  • Mybatis的一級(jí)緩存存在于sqlSession的生命周期中,在同一個(gè)SqlSession中查詢時(shí),MyBatis會(huì)把執(zhí)行方法和參數(shù)通過(guò)算法 生成緩存的鍵值,將鍵值和查詢結(jié)果存入一個(gè)Map對(duì)象中。如果同一個(gè)SqlSession中執(zhí)行的方法和參數(shù)完全一致,就會(huì)直接去Map中的鍵值匹配??梢酝ㄟ^(guò)設(shè)置方法中的flushCache屬性取消一級(jí)緩存。
  • 當(dāng)執(zhí)行delete、update、insert后都會(huì)清空一級(jí)緩存。

二級(jí)緩存

  • MyBatist的二級(jí)緩存非常強(qiáng)大,存在于SqlSessionFactory的生命周期中。當(dāng)存在多個(gè)SqlSessionFactory時(shí),它們的緩存都是綁定在各自的對(duì)象上的,緩存數(shù)據(jù)一般情況下不能相痛!只有使用如Redis這樣的緩存數(shù)據(jù)庫(kù)時(shí),才能共享緩存。
使用方法:

在Mapper.xml的<mapper>便簽中添加<cache/>。
默認(rèn)的二級(jí)緩存有如下的效果:

  • 映射語(yǔ)句中的所以SELECT語(yǔ)句將會(huì)被緩存。
  • 映射語(yǔ)句中的所以INSERT、UPDATE、DELETE語(yǔ)句會(huì)刷新緩存。
  • 緩存會(huì)使用Least Recently Used算法回收。
  • 根據(jù)時(shí)間表刷新,緩存不會(huì)以任何的時(shí)間順序刷新。//只是默認(rèn)的情況
  • 緩存會(huì)存儲(chǔ)集合或?qū)ο蟮?024個(gè)引用。(無(wú)論方法返回的什么類型的值)
  • 緩存都會(huì)視為read/write。意味著對(duì)象檢索不是共享的,而且可以安全地被調(diào)用者修改,而不干擾其他調(diào)用者或線程所做的修改。

使用方法:

  • 在接口中添加標(biāo)簽@CacheNamespace

或者

  • 在mapper.xml中添加<cache/>

實(shí)例:

<cache
        eviction="FIFO"
        flushInterval="60000"
        size="512"
        readOnly="false"/>

使用二級(jí)緩存:

  • 配置好二級(jí)緩存之后,當(dāng)調(diào)用所以的select查詢方法時(shí),二級(jí)緩存就會(huì)開(kāi)始起作用了。注意的是,由于配置的是可讀可寫(xiě)緩存,而MyBatis使用SerializedCache序列化緩存來(lái)實(shí)現(xiàn)可讀可寫(xiě)緩存類,并通過(guò)序列化和反序列化來(lái)保證通過(guò)緩存獲取數(shù)據(jù)時(shí),得到的是一個(gè)新的實(shí)例.因此,如果配置只讀緩存,MyBatis就會(huì)使用Map來(lái)存儲(chǔ)緩存值,這種情況下,從緩存里得到的都是同一個(gè)對(duì)象。
  • 因?yàn)槭褂每勺x寫(xiě)緩存,所以這個(gè)緩存類要求所有被序列化的對(duì)象必須實(shí)現(xiàn)Serializable接口。

測(cè)試代碼:

    @Test
    public void testL2Cache() {
        SqlSession sqlSession = getSqlSession();
        SysRole sysRole = null;
        try {
            RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
            sysRole = roleMapper.selectById(1l);
            sysRole.setRoleName("new name");

            SysRole sysRole1 = roleMapper.selectById(1l);

            Assert.assertEquals("new name", sysRole1.getRoleName());
            //一級(jí)緩存,兩個(gè)查詢相同的對(duì)象是相同的
            Assert.assertEquals(sysRole, sysRole1);
        } finally {
            sqlSession.close();
        }
        System.out.println("開(kāi)始另一個(gè)查詢");

        sqlSession = getSqlSession();
        try {
            RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);

            SysRole sysRole1 = roleMapper.selectById(1l);

            Assert.assertEquals("new name", sysRole1.getRoleName());

            Assert.assertNotEquals(sysRole, sysRole1);

            SysRole sysRole2 = roleMapper.selectById(1l);

            // sysRole1 sysRole2是兩個(gè)反序列化得到的結(jié)果,是不相同的實(shí)例
            Assert.assertNotEquals(sysRole1, sysRole2);
        } finally {
            sqlSession.close();
        }
    }

運(yùn)行結(jié)果截圖:


二級(jí)緩存
  • 日志中存在好幾條以Cache Hit Ratio開(kāi)頭的語(yǔ)句,這行日志后面輸出的值為當(dāng)前執(zhí)行方法的緩存命中率。但是在這個(gè)例子中并沒(méi)有真正的讀寫(xiě)安全。因?yàn)闇y(cè)試中加入了一行不該有的代碼,sysRole.setRoleName("new name");按照常理應(yīng)該更新數(shù)據(jù),更新后會(huì)清空一級(jí)、二級(jí)緩存,這樣在第二部分的代碼中就不出出現(xiàn)查詢結(jié)果的roleName都是“new name”的結(jié)果。所以想要安全使用,就要避免出現(xiàn)毫無(wú)意義的修改。這樣就可以避免認(rèn)為的臟數(shù)據(jù),避免緩存和數(shù)據(jù)庫(kù)的數(shù)據(jù)不一致。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 主題是Mybatis一級(jí)和二級(jí)緩存的應(yīng)用及源碼分析。希望在本場(chǎng)chat結(jié)束后,能夠幫助讀者朋友明白以下三點(diǎn)。...
    余平的余_余平的平閱讀 1,430評(píng)論 0 12
  • 原文:https://tech.meituan.com/mybatis_cache.html 前言 MyBatis...
    laosijikaichele閱讀 2,619評(píng)論 1 27
  • 緩存技術(shù)是一種“以空間換時(shí)間”的設(shè)計(jì)理念,是利用內(nèi)存空間資源來(lái)提高數(shù)據(jù)檢索速度的有效手段之一。Mybatis包含一...
    不知名的蛋撻閱讀 4,249評(píng)論 0 7
  • 1、概述 Mybatis的緩存大體上分為一級(jí)緩存和二級(jí)緩存,我們先來(lái)說(shuō)下一級(jí)緩存。 2、一級(jí)緩存 ??當(dāng)我們使用M...
    騎著烏龜去看海閱讀 1,031評(píng)論 3 3
  • 大海是個(gè)普通人,但是他總是想不起來(lái)這點(diǎn)! 一天,伙伴邀他一起去爬山,他很猶豫,但是拗不過(guò)伙伴們的勸說(shuō),就同意了,浩...
    雨中的玫瑰閱讀 381評(píng)論 0 0

友情鏈接更多精彩內(nèi)容