溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java?Mybatis一級(jí)緩存和二級(jí)緩存是什么

發(fā)布時(shí)間:2023-04-07 10:55:05 來源:億速云 閱讀:166 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“Java Mybatis一級(jí)緩存和二級(jí)緩存是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Java Mybatis一級(jí)緩存和二級(jí)緩存是什么”吧!

一、什么是緩存 

        緩存是內(nèi)存當(dāng)中一塊存儲(chǔ)數(shù)據(jù)的區(qū)域,目的是提高查詢效率。MyBatis會(huì)將查詢結(jié)果存儲(chǔ)在緩存當(dāng)中,當(dāng)下次執(zhí)行相同的SQL時(shí)不訪問數(shù)據(jù)庫,而是直接從緩存中獲取結(jié)果,從而減少服務(wù)器的壓力。

什么是緩存?

存在于內(nèi)存中的一塊數(shù)據(jù)。

緩存有什么作用?

減少程序和數(shù)據(jù)庫的交互,提高查詢效率,降低服務(wù)器和數(shù)據(jù)庫的壓力。

什么樣的數(shù)據(jù)使用緩存?

經(jīng)常查詢但不常改變的,改變后對(duì)結(jié)果影響不大的數(shù)據(jù)。

MyBatis緩存分為哪幾類?

 一級(jí)緩存和二級(jí)緩存

如何判斷兩次Sql是相同的?

查詢的Sql語句相同 傳遞的參數(shù)值相同 對(duì)結(jié)果集的要求相同 預(yù)編譯的模板Id相同

二、Mabtis一級(jí)緩存

MyBatis一級(jí)緩存也叫本地緩存。SqlSession對(duì)象中包含一個(gè)Executor對(duì)象,Executor對(duì)象中包含一個(gè)PerpetualCache對(duì)象,在該對(duì)象存放一級(jí)緩存數(shù)據(jù)。

由于一級(jí)緩存是在SqlSession對(duì)象中,所以只有使用同一個(gè)SqlSession對(duì)象操作數(shù)據(jù)庫時(shí)才能共享一級(jí)緩存。

MyBatis的一級(jí)緩存是默認(rèn)開啟的,不需要任何的配置。

如下圖所示:

Java?Mybatis一級(jí)緩存和二級(jí)緩存是什么

(1)測(cè)試一級(jí)緩存

其實(shí)測(cè)試方法很簡單,就是通過使用相同和不同的SqlSession對(duì)象進(jìn)行SQL查詢,返回的對(duì)象的哈希值是否一樣就可以知道了,如果返回的哈希值一樣說明沒有進(jìn)行SQL查詢,而是直接從緩存拿到對(duì)象來返回

下面是使用相同的Session對(duì)象來執(zhí)行查詢,如果觀察user1和user2的哈希值一樣則說明確實(shí)開啟了一級(jí)緩存,并沒有進(jìn)行查詢,而是直接從緩存中拿數(shù)據(jù)。 

import com.mybatisstudy.mapper.UserMapper;
import com.mybatisstudy.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
 
import java.io.InputStream;
 
public class TestUserMapper3 {
    // 測(cè)試使用同一個(gè)SqlSession查詢
    @Test
    public void testCache1() throws Exception{
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(is);
        SqlSession session = factory.openSession();
 
        // 使用同一個(gè)SqlSession查詢
        UserMapper mapper1 = session.getMapper(UserMapper.class);
        UserMapper mapper2 = session.getMapper(UserMapper.class);
 
        User user1 = mapper1.findById(1);
        System.out.println(user1.hashCode());
        System.out.println("------------------------------------------");
        User user2 = mapper2.findById(1);
        System.out.println(user2.hashCode());
 
        session.close();
    }
}

執(zhí)行結(jié)果 

Java?Mybatis一級(jí)緩存和二級(jí)緩存是什么

        OK,確實(shí)返回的哈希值都是一樣的,并且我們可以通過控制臺(tái)輸出顯示它并沒有進(jìn)行查詢而是直接從緩存中拿到對(duì)象并返回,所以這就是一級(jí)緩存 ,提高了查詢效率。

        下面使用不同的SqlSession來進(jìn)行測(cè)試一下,返回的哈希值是否一致 

// 測(cè)試使用不同SqlSession查詢
    @Test
    public void testCache2() throws Exception{
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(is);
        SqlSession session1 = factory.openSession();
        SqlSession session2 = factory.openSession();
 
        // 測(cè)試使用不同SqlSession查詢
        UserMapper mapper1 = session1.getMapper(UserMapper.class);
        UserMapper mapper2 = session2.getMapper(UserMapper.class);
 
        User user1 = mapper1.findById(1);
        System.out.println(user1.hashCode());
        System.out.println("---------------------------------");
        User user2 = mapper2.findById(1);
        System.out.println(user2.hashCode());
 
        session1.close();
        session2.close();
    }

運(yùn)行結(jié)果

Java?Mybatis一級(jí)緩存和二級(jí)緩存是什么

        OK,可以看到,返回的哈希值不一樣,并且從控制臺(tái)輸出顯示也可以看到這里的確也進(jìn)行了一次查詢,因此可以證實(shí),共享一級(jí)緩存確實(shí)是基于SqlSession對(duì)象的 

(2)清空一級(jí)緩存

        但是吧,如果緩存過多的話,也是會(huì)影響我們的查詢效率的,所以這時(shí)候就需要清空緩存了,就像我們時(shí)不時(shí)要清理一下手機(jī)緩存否則就會(huì)很卡,是同樣的道理,那怎么清空一級(jí)緩存呢?

進(jìn)行以下操作可以清空MyBatis一級(jí)緩存:

  • SqlSession 調(diào)用 close() :操作后SqlSession對(duì)象不可用,該對(duì)象的緩存數(shù)據(jù)也不可用。

  • SqlSession 調(diào)用 clearCache() / commit() :操作會(huì)清空一級(jí)緩存數(shù)據(jù)。

  • SqlSession 調(diào)用增刪改方法:操作會(huì)清空一級(jí)緩存數(shù)據(jù),因?yàn)樵鰟h改后數(shù)據(jù)庫發(fā)生改變,緩存數(shù)據(jù)將不準(zhǔn)確

// 清空Mybatis一級(jí)緩存
    @Test
    public void testCache3() throws Exception{
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(is);
        SqlSession session = factory.openSession();
 
        UserMapper mapper1 = session.getMapper(UserMapper.class);
        UserMapper mapper2 = session.getMapper(UserMapper.class);
 
        User user1 = mapper1.findById(1);
        System.out.println(user1.hashCode());
 
        // 清空Mybatis一級(jí)緩存
        session.clearCache();
 
        System.out.println("-------------------------------");
        User user2 = mapper2.findById(1);
        System.out.println(user2.hashCode());
 
        session.close();
    }

執(zhí)行效果

Java?Mybatis一級(jí)緩存和二級(jí)緩存是什么

        OK,返回的哈希值也確實(shí)不一樣, 但是我們有沒有觀察到這和上面使用不同的SqlSession對(duì)象來執(zhí)行查詢的時(shí)候,控制臺(tái)輸入顯示有點(diǎn)不一樣,那就是這里不用再建立JDBC連接,也有效了提高查詢效率,所以我們偶爾還是要清空一下緩存才行

三、Mybatis二級(jí)緩存

MyBatis二級(jí)緩存也叫全局緩存。數(shù)據(jù)存放在SqlSessionFactory中,只要是同一個(gè)工廠對(duì)象創(chuàng)建的SqlSession,在進(jìn)行查詢時(shí)都能共享數(shù)據(jù)。一般在項(xiàng)目中只有一個(gè)SqlSessionFactory對(duì)象,所以二級(jí)緩存的數(shù)據(jù)是全項(xiàng)目共享的。
MyBatis一級(jí)緩存存放的是對(duì)象,二級(jí)緩存存放的是對(duì)象的數(shù)據(jù)。所以要求二級(jí)緩存存放的POJO必須是可序列化的,也就是要實(shí)現(xiàn)Serializable接口。
MyBatis二級(jí)緩存默認(rèn)不開啟,手動(dòng)開啟后數(shù)據(jù)先存放在一級(jí)緩存中,只有一級(jí)緩存數(shù)據(jù)清空后,數(shù)據(jù)才會(huì)存到二級(jí)緩存中。           
SqlSession 調(diào)用 clearCache() 無法將數(shù)據(jù)存到二級(jí)緩存中。

(1)開啟二級(jí)緩存

1. POJO類實(shí)現(xiàn)Serializable接口

import java.io.Serializable;
 
public class User implements Serializable {
    private int id;
    private String username;
    private String sex;
    private String address;
}

2. 在Mybatis配置文件添加如下設(shè)置

<!-- 二級(jí)緩存打開 -->
<settings>   
 <setting name="cacheEnabled" value="true"/>
</settings>

這里有個(gè)額外知識(shí),就是Mybatis配置文件的標(biāo)簽還得按照順序來放的,否則就會(huì)以下編譯錯(cuò)誤;

The content of element type "configuration" must match "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,

objectWrapperFactory?,reflectorFactory?,plugins?,environments?,

databaseIdProvider?,mappers?)". 

  同時(shí)也說明了放置順序就得按照match里面的順序來放

3. 添加 <cache /> 標(biāo)簽

 如果查詢到的集合中對(duì)象過多,二級(jí)緩存只能緩存1024個(gè)對(duì)象引用??梢酝ㄟ^

<cache /> 標(biāo)簽的size屬性修改該數(shù)量。

比如:<cache size="2048"/>

(2)測(cè)試二級(jí)緩存

        那怎么測(cè)試呢,從上面我們可以知道二級(jí)緩存存放的是對(duì)象的數(shù)據(jù),并且是基于SqlSessionFactory的,因此我們可以用SqlSessionFactory獲取兩個(gè)SqlSession對(duì)象,然后讓他們分別獲取各自的mapper,然后進(jìn)行查詢,返回到同一個(gè)實(shí)例化的USer對(duì)象中,如果返回的數(shù)據(jù)是一致的,但是對(duì)象的哈希值是不一樣的話,則說明二級(jí)緩存里存放的確實(shí)對(duì)象的數(shù)據(jù)而不是對(duì)象。

// 測(cè)試二級(jí)緩存
@Test
public void testCache4() throws Exception {
    InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory factory = builder.build(is);
    SqlSession session = factory.openSession();

    UserMapper mapper1 = session.getMapper(UserMapper.class);
    UserMapper mapper2 = session.getMapper(UserMapper.class);

    User user1 = mapper1.findById(1);
    System.out.println(user1);
    System.out.println(user1.hashCode());

    // 讓一級(jí)緩存失效
    session.commit();
    System.out.println("----------------------------");

    user1 = mapper2.findById(1);
    System.out.println(user1);
    System.out.println(user1.hashCode());
}

運(yùn)行結(jié)果 

Java?Mybatis一級(jí)緩存和二級(jí)緩存是什么

        OK,從運(yùn)行結(jié)果上我們可以知道結(jié)果集返回到同一個(gè)對(duì)象中,而他們的哈希值反而不一樣,說明執(zhí)行第二次查詢的時(shí)候新建了一個(gè)對(duì)象并且該對(duì)象指向那個(gè)對(duì)象并且將SqlSessionFactory中的數(shù)據(jù)賦值到新建的那個(gè)對(duì)象。其實(shí)從控制臺(tái)打印的日志我們也可以得出,并沒有執(zhí)行查詢方法,因?yàn)闆]有打印SQL語句,而且緩存也是從0.0改成了0.5,因此我們可以斷定二級(jí)緩存存放的是數(shù)據(jù)而不是對(duì)象。

到此,相信大家對(duì)“Java Mybatis一級(jí)緩存和二級(jí)緩存是什么”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI