MyBatis | 一級緩存與二級緩存

一、什么是緩存?

緩存,合理使用緩存是優(yōu)化中最常見的,將從數(shù)據(jù)庫中查詢出來的數(shù)據(jù)放入緩存中,下次使用時不必從數(shù)據(jù)庫查詢,而是直接從緩存中讀取,避免頻繁操作數(shù)據(jù)庫,減輕數(shù)據(jù)庫的壓力,同時提高系統(tǒng)性能。


一級緩存:是 SQlSession 級別的緩存。在操作數(shù)據(jù)庫時需要構(gòu)造 SqlSession 對象,在對象中有一個數(shù)據(jù)結(jié)構(gòu)(HashMap)用于存儲緩存數(shù)據(jù)。不同的 SqlSession 之間的緩存數(shù)據(jù)區(qū)域(HashMap)是互相不影響的。

二級緩存:是 mapper 級別的緩存,多個 SqlSession 去操作同一個mapper的sql語句,多個 SqlSession 可以共用二級緩存,二級緩存是跨 SqlSession 的。

二、具體介紹

1.使用一級緩存

我們先看一個使用緩存例子:這里我們是根據(jù)傳入的 id 獲取 Employee 對象的值,我們先使用同一個 SqlSession 對象,并且查詢 id 相同的對象

@Test
public void testFirstCache() throws IOException {
    SqlSessionFactory sqlSessionFactory = Utils.getSqlSessionFactoty();
    SqlSession openSession = sqlSessionFactory.openSession();
    
    try {
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        Employee employee = mapper.getEmployee(1);
        System.out.println(employee);
            
        Employee employee2 = mapper.getEmployee(1);
        System.out.println(employee2);
        System.out.println(employee==employee2);    
    } finally {
        openSession.close();
    }
    
}

他的運行結(jié)果是:

從結(jié)果中可以看出,第一次查詢結(jié)束之后,就把 id 為 1 的數(shù)據(jù)放入到緩存中(本質(zhì)上是放入 Map 對象中),第二次如果還是使用相同的 SqlSession 對象,則先會去一級緩存中找是否有 id 為 1 的員工的信息(Map 對象中是否有該對象),如果有,則直接從緩存中取出員工信息,如果沒有,則會去數(shù)據(jù)庫中查詢相關(guān)信息

我們再來看一個一級緩存失效了的例子:假設(shè)這個時候我們查詢的不是同一個 id,我們看看結(jié)果是怎樣。在上面的代碼中,我們將 Employee employee2 = mapper.getEmployee(1) 改為 Employee employee2 = mapper.getEmployee(2),即不是查詢同一個 id,結(jié)果如下:

這也驗證了我上面的結(jié)論

一級緩存失效的情況
  • SqlSession 對象不同, 導(dǎo)致每次使用的都是新的 SqlSession 對象
  • SqlSession 相同, 查詢條件不同, 此時一級緩存中沒有數(shù)據(jù), 因為兩次查詢的內(nèi)容不一樣
  • SqlSession 相同, 兩次查詢直接執(zhí)行了增刪改查操作, 因為這次操作可能會對當(dāng)前數(shù)據(jù)庫有影響
  • SqlSession 相同, 手動清除了一級緩存(openSession.clearCache()

這些情況就不一一舉例了,以后用到關(guān)注一下即可

2. 使用二級緩存

EmployeeMapper 有一個二級緩存區(qū)域(按 namespace 分),其它 Mapper 也有自己的二級緩存區(qū)域(按 namespace 分)。每一個 namespace 的 mapper 都有一個二級緩存區(qū)域,兩個 mapper 的 namespace 如果相同,這兩個 mapper 執(zhí)行 sql 查詢到數(shù)據(jù)將存在相同的二級緩存區(qū)域中。


2.1 工作機(jī)制

  1. 一個會話, 查詢一條數(shù)據(jù), 這個數(shù)據(jù)就會被保存在當(dāng)前會話的一次緩存(SqlSession)中
  2. 如果關(guān)閉會話, 那么一次緩存中的數(shù)據(jù)就會被保存到二級緩存(namespace)中,新的會話查詢的內(nèi)容, 就可以參照二級緩存
  3. 一個 xxxMapper 對應(yīng)一個 namespace, 不同的 namespace 查出的數(shù)據(jù)會保存在自己對應(yīng)的二級緩存中
  4. 查出的數(shù)據(jù)會先被保存在一級緩存中, 只有會話關(guān)閉或者提交之后, 以及緩存中的數(shù)據(jù)才會被轉(zhuǎn)移到二級緩存

2.2 開啟二級緩存步驟

  1. 開啟全局二級緩存配置
  2. 去 mapper.xml 中配置使用二級緩存
  3. 我們的 POJO 需要實現(xiàn)序列化接口

在全局文件中開啟二級緩存

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

在 sql 映射文件中配置使用二級緩存,具體參數(shù)可以去官方文檔查詢

<mapper namespace="edu.just.mybatis.dao.EmployeeMapper">
    <cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"></cache>
    ...
</mapper>

實現(xiàn)序列化

public class Employee implements Serializable{

    private static final long serialVersionUID = 1L;
    
    private Integer id;
    private String lastName;
    private String email;
    private Integer gender;
    private Department department;

        ...
}


2.3 二級緩存測試
這里我們通過兩個不同的 SqlSession 對象創(chuàng)建兩個 EmployeeMapper,這兩個 EmployeeMapper 屬于同一個 namespace

@Test
public void testSecondCache() throws IOException {
    SqlSessionFactory sqlSessionFactory = Utils.getSqlSessionFactoty();
    SqlSession openSession = sqlSessionFactory.openSession();
    SqlSession openSession2 = sqlSessionFactory.openSession();
        
    try {
        //1.創(chuàng)建兩個不同的 EmployeeMapper 對象
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
            
        Employee employee = mapper.getEmployee(1);
        openSession.close();          //關(guān)閉第第一個 SqlSession 會話
            
        //2.第二次查詢是從二級緩存中拿到的, 并沒有發(fā)送新的 sql
        //  此時是從 EmployeeMapper 的二級緩存中獲取的數(shù)據(jù)
        Employee employee2 = mapper2.getEmployee(1);
        System.out.println(employee2);
        openSession.close();
        
    } finally {
        openSession.close();
    }
}

結(jié)果如下:

可以看到,雖然我們使用的是兩個 SqlSession 對象,但是范圍依舊是在 EmployeeMapper 這個 namespace 中,當(dāng)我們關(guān)閉了第一個 SqlSession 對象后,此時第一次緩存中的數(shù)據(jù)被保存在了 EmployeeMapper 的二級緩存中,因此當(dāng)我們重新查詢相同的 id 的數(shù)據(jù)時,這個時候是在二級緩存中進(jìn)行獲取的

2.4 其他配置
①. cacheEnabled 設(shè)置的是二級緩存,一級緩存也一直可以使用
②. 每個 select 標(biāo)簽都有 useCache 標(biāo)簽,如果設(shè)置 useCache="false",那么一級緩存依舊使用,二級緩存則不會使用
③. 每個增刪改查操作的 flushCache="true", 表示增刪改查操作完成之后, 會自動清除緩存, 此時一級緩存和二級緩存都會被清空

三、參考

深入理解MyBatis中的一級緩存與二級緩存
【MyBatis學(xué)習(xí)13】MyBatis中的二級緩存

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 前言 主題是Mybatis一級和二級緩存的應(yīng)用及源碼分析。希望在本場chat結(jié)束后,能夠幫助讀者朋友明白以下三點。...
    余平的余_余平的平閱讀 1,414評論 0 12
  • 參考互聯(lián)網(wǎng)后端架構(gòu)的文章 一級緩存 一級緩存是SqlSession級別的緩存。在操作數(shù)據(jù)庫時需要構(gòu)造sqlSess...
    wangxiaoda閱讀 1,978評論 0 4
  • Tensorflow函數(shù)大全 操作函數(shù) 正則化 一 數(shù)據(jù)處理 v1 = [1.0,2.0,3.0,4.0] ...
    lolipops閱讀 1,243評論 0 1
  • 凌晨三點半,因為作業(yè)沒交睡不踏實,索性開燈起來寫。 如果人生是本書,我已然在后半部。前半部完成于2015年,當(dāng)看到...
    無盡蔓閱讀 297評論 2 5
  • 16年如果里程碑一件是兒子出生,一件是加入培訓(xùn)師俱樂部,還有一件就是跳槽。 培訓(xùn)師俱樂部作為我的家,鍛煉了演講技巧...
    DennisFly閱讀 467評論 0 0

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