溫馨提示×

溫馨提示×

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

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

MyBatis中的一級(jí)和二級(jí)緩存怎么用

發(fā)布時(shí)間:2021-12-30 09:46:10 來源:億速云 閱讀:139 作者:小新 欄目:大數(shù)據(jù)

這篇文章主要為大家展示了“MyBatis中的一級(jí)和二級(jí)緩存怎么用”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“MyBatis中的一級(jí)和二級(jí)緩存怎么用”這篇文章吧。


1.1 什么是緩存

緩存是存在內(nèi)存中的臨時(shí)數(shù)據(jù),通過將我們 「經(jīng)常查詢但不常變的數(shù)據(jù)」 放在內(nèi)存中,當(dāng)我們查詢數(shù)據(jù)時(shí)就不在需要從磁盤讀取,而只需要從緩存中查詢即可,大大提升了查詢的效率,解決了高并發(fā)系統(tǒng)的性能問題。

 

1.2 為什么需要緩存

既然我們可以直接從數(shù)據(jù)庫中查詢數(shù)據(jù),那為什么還要需要緩存呢?通過使用緩存,我們能夠減少和數(shù)據(jù)庫之間的交互頻率,減少系統(tǒng)開銷,從而提高系統(tǒng)的效率。

 

2. MyBatis 緩存

MyBatis 內(nèi)置了一個(gè)強(qiáng)大的事務(wù)性查詢緩存機(jī)制,通過它能夠十分方便的配置和定制。默認(rèn)情況下,MyBatis 默認(rèn)定義了兩級(jí)緩存,而且為了提高擴(kuò)展性,定義了緩存接口 Cache,我們能十分方便的實(shí)現(xiàn) Cache 接口來自定義二級(jí)緩存。

  • 「一級(jí)緩存」:也叫      「本地緩存」,默認(rèn)情況下開啟的緩存(      SqlSession 級(jí)別的緩存);
  • 「二級(jí)緩存」:基于      namespace 級(jí)別的緩存,需要我們手動(dòng)進(jìn)行開啟和配置;
 

3. 一級(jí)緩存

也叫 「本地緩存」,在與數(shù)據(jù)庫同一次會(huì)話期間查詢到的數(shù)據(jù)放在本地緩存,當(dāng)要再次獲取相同數(shù)據(jù)時(shí),直接從緩存獲取即可,不用再次和數(shù)據(jù)庫交互。

 

3.1 一級(jí)緩存原理

MyBatis中的一級(jí)和二級(jí)緩存怎么用  

每個(gè) SqlSession 中都有一個(gè) Executor,每個(gè) Executor 中又有一個(gè) LocalCache,當(dāng)我們進(jìn)行查詢操作時(shí),MyBatis 根據(jù)當(dāng)前執(zhí)行的語句生成 MapperdStatement,然后在 Local Cache 中進(jìn)行查詢,如果存在(命中),直接返回給用戶。若緩存中不存在(未命中),則和數(shù)據(jù)庫交互查詢數(shù)據(jù),將結(jié)果寫入 Local Cache,同時(shí)返回給用戶。

 

3.2 如何使用一級(jí)緩存

一級(jí)緩存即 SqlSession 級(jí)別的緩存,和我們之前的 CURD 操作差不多;

  1. 首先在接口中添加方法;
@Select("select * from user where id=#{id}")
User queryUserById(@Param("id") int id);
 
  1. 測試
@Test
public void testQueryUserById() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);

    User user1 = mapper.queryUserById(1);
    System.out.println(user1);

    User user2 = mapper.queryUserById(1);
    System.out.println(user2);

    System.out.println(user1 == user2);

    sqlSession.close();
}
 
  1. 結(jié)果
MyBatis中的一級(jí)和二級(jí)緩存怎么用  

通過結(jié)果可以看出,由于是在一次會(huì)話期間內(nèi)(SqlSession 級(jí)別),所以此時(shí)的 SQL 語句只查詢了一次,當(dāng)?shù)诙潍@取相同結(jié)果時(shí),直接從緩存中取結(jié)果即可,也就解釋了為什么 user1user2 指向的是同一個(gè)對(duì)象;

 

3.3 一級(jí)緩存失效的情況

一級(jí)緩存是默認(rèn)一直開啟的,我們是關(guān)閉不了的。但是有時(shí)候一級(jí)緩存會(huì)出現(xiàn)失效的情況,主要可能是如下幾種原因?qū)е拢?/p>

  1. 「每個(gè) SqlSession 中緩存獨(dú)立」

當(dāng)我們使用不同的 SqlSession 時(shí),有多少個(gè) SqlSession 就需要向數(shù)據(jù)庫發(fā)起多少次查詢請(qǐng)求。

@Test
public void testQueryUserById() {
    SqlSession sqlSession1 = MybatisUtil.getSqlSession();
    UserDao mapper1 = sqlSession1.getMapper(UserDao.class);

    SqlSession sqlSession2 = MybatisUtil.getSqlSession();
    UserDao mapper2 = sqlSession2.getMapper(UserDao.class);

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

    User user2 = mapper2.queryUserById(1);
    System.out.println(user2);

    System.out.println(user1 == user2);

    sqlSession1.close();
    sqlSession2.close();
}
 
MyBatis中的一級(jí)和二級(jí)緩存怎么用  
  1. 「當(dāng)前緩存中不存在該數(shù)據(jù)時(shí)」

當(dāng)位于同一個(gè) SqlSession,但查詢條件不同時(shí),也會(huì)導(dǎo)致緩存失效;

@Test
    public void testQueryUserById1() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);

        User user = mapper.queryUserById(1);
        System.out.println(user);

        User user2 = mapper.queryUserById(2);
        System.out.println(user2);

        System.out.println(user == user2);

        sqlSession.close();
    }
 
MyBatis中的一級(jí)和二級(jí)緩存怎么用  
  1. 「其他 CURD 操作對(duì)當(dāng)前數(shù)據(jù)造成影響」

假如在同一 SqlSession 中,在兩次查詢之間進(jìn)行了其他的增刪改等操作,當(dāng)?shù)诙尾樵冞M(jìn)行時(shí),就會(huì)重新執(zhí)行 SQL 語句,導(dǎo)致緩存失效;

@Test
public void testQueryUserById() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);

    User user = mapper.queryUserById(1);
    System.out.println(user);

    mapper.updateUser(new User(2,"小玉","8349823"));

    User user2 = mapper.queryUserById(1);
    System.out.println(user2);

    System.out.println(user == user2);

    sqlSession.close();
}
 
MyBatis中的一級(jí)和二級(jí)緩存怎么用  
  1. 「手動(dòng)清除」

當(dāng) SqlSession 相同時(shí),如果我們手動(dòng)清除了緩存,那么也會(huì)導(dǎo)致緩存失效的情況出現(xiàn)。

@Test
public void testQueryUserById1() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);

    User user = mapper.queryUserById(1);
    System.out.println(user);

    // 手動(dòng)清除緩存
    sqlSession.clearCache();

    User user2 = mapper.queryUserById(1);
    System.out.println(user2);

    System.out.println(user == user2);

    sqlSession.close();
}
 
MyBatis中的一級(jí)和二級(jí)緩存怎么用  
 

4. 二級(jí)緩存

也叫 「全局緩存」,基于 namespace 的緩存,一個(gè) namespace 對(duì)應(yīng)一個(gè)二級(jí)緩存。

 

4.1 二級(jí)緩存原理

MyBatis中的一級(jí)和二級(jí)緩存怎么用  

一級(jí)緩存的最大共享范圍是一個(gè) SqlSession 內(nèi)部,若多個(gè) SqlSession 之間要共享緩存,則需要用二級(jí)緩存。二級(jí)緩存一旦開啟,將會(huì)有多個(gè) CachingExecutor 來裝飾 Executor,進(jìn)入一級(jí)緩存的查詢流程之前,先在 CachingExecutor 中進(jìn)行二級(jí)緩存的查詢,如上圖。此時(shí)數(shù)據(jù)的查詢流程是:

?

二級(jí)緩存 -> 一級(jí)緩存 -> 數(shù)據(jù)庫

?  
 

4.2 如何使用二級(jí)緩存

要使用二級(jí)緩存,通常需要有如下步驟:

  1. 首先在 MyBatis 配置文件(一般是      mybatis-config.xml)中開啟二級(jí)緩存;
<setting name="cacheEnabled" value="true"/>
 
  1. 然后到對(duì)應(yīng)的      xxxMapper.xml 中配置二級(jí)緩存;
<cache/>
 

配置之后,xxxMapper.xml 文件中的 select 語句將會(huì)被緩存,而 insert、update、delete 則會(huì)刷新緩存。此外還可以設(shè)置自定義屬性值來修改默認(rèn)屬性;

屬性說明
eviction清除策略
flushInterval刷新間隔,單位是 ms
size引用數(shù)目,默認(rèn)為 1024
readOnly默認(rèn)為 false

而清除策略也主要有如下 4 種:

清除策略說明
LRU「最近最少使用」:移除最長時(shí)間不被使用的對(duì)象
FIFO「先進(jìn)先出」:按對(duì)象進(jìn)入緩存的順序來移除
SOFT「軟引用」:基于垃圾回收器狀態(tài)和軟引用規(guī)則移除對(duì)象
WEAK「弱引用」:更積極地基于垃圾回收器狀態(tài)和若引用規(guī)則移除對(duì)象
  1. 測試
@Test
public void testGetUserByPassword() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    SqlSession sqlSession2 = MybatisUtils.getSqlSession();

    UserDao mapper = sqlSession.getMapper(UserDao.class);
    UserDao mapper2 = sqlSession.getMapper(UserDao.class);

    User user = mapper.getUserByPassword("1234567");
    System.out.println(user);


    User user2 = mapper2.getUserByPassword("1234567");
    System.out.println(user2);
    System.out.println(user==user2);

    sqlSession.close();
    sqlSession2.close();
}
 
  1. 結(jié)果
MyBatis中的一級(jí)和二級(jí)緩存怎么用  

根據(jù)結(jié)果可以看出,此時(shí)的二級(jí)緩存已經(jīng)生效。若是未生效,則會(huì)和一級(jí)緩存中的結(jié)果一致,兩者指向不同的對(duì)象,但此時(shí)兩個(gè)引用指向同一對(duì)象,說明二級(jí)緩存成功。


以上是“MyBatis中的一級(jí)和二級(jí)緩存怎么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向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