MyBatis包含一個非常強大的查詢緩存特性,它可以非常方便地定製和配置緩存。緩存可以極大的提升查詢效率。
MyBatis系統中默認定義了兩級緩存:一級緩存和二級緩存
- 默認情況下,只有一級緩存開啓。(SqlSession級別的緩存, 也稱爲本地緩存)
- 二級緩存需要手動開啓和配置,他是基於namespace級別的緩存。
- 爲了提高擴展性,MyBatis定義了緩存接口Cache。我們可以通過實現Cache接口來自定義二級緩存
緩存作用效果
- select 語句的結果將會被緩存。
- insert、update 和delete語句會刷新緩存。
- 緩存會使用最近最少使用算法(LRU)算法來清除不需要的緩存。
- 緩存不會定時進行刷新
- 緩存會保存列表或對象的1024個引用。
- 緩存會被視爲讀/寫緩存,這意味着獲取到的對象並不是共享的,可以安全地被調用者修改,而不干擾其他調用者或線程所做的潛在修改。
- 緩存只作用於cache標籤所在的映射文件中的語句
一級緩存
默認開啓,只在一個SqlSession中有效
package com.robot.dao;
import com.robot.pojo.User;
import com.robot.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class MyTest {
@Test
public void userTest() {
// 從開啓sqlSession,到關閉爲止,中間都屬於一級緩存
// 查出的內容會被緩存,在之間第二次查同樣的數據時,直接在緩存中拿,無需再去數據庫中查
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
System.out.println(user);
User user2 = mapper.queryUserById(1);
System.out.println(user);
sqlSession.close();
}
}
由以上結果可以看到,第一次查詢出 id=1 的用戶時,執行了查詢語句以及顯示出一些信息,而第二次再次查詢 id=1 的用戶時,因爲緩存中已經有了,所以直接在緩存中取出數據即可
二級緩存
基於namespace級別的緩存,一個空間名稱,對應一個二級緩存
工作機制
- 一個會話查詢一條數據,這個數據就會被放在當前會話的一級緩存中;
- 如果當前會話關閉了,這個會話對應的一級緩存就沒了,但是我們想要的是,會話關閉了,一級緩存中的數據被保存到二級緩存中
- 新的會話查詢信息,就可以從二級緩存中獲取內容;
- 不同的mapper查出的數據會放在自己對應的緩存(map) 中;
第一步:開啓全局緩存
配置 mybatis-config.xml
<setting name="cacheEnabled" value="true"/>
第二步:在當前Mapper中使用二級緩存
配置 UserMapper.xml
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
第三步:測試
@Test
public void cache2Test() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
SqlSession sqlSession2 = MybatisUtils.getSqlSession();
// 當一級緩存關閉時,會將緩存內容傳給二級緩存
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
System.out.println(user);
sqlSession.close();
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
User user2 = mapper2.queryUserById(1);
System.out.println(user2);
System.out.println(user==user2);
sqlSession2.close();
}
以上可以看到,當第一個會話關閉後,第二次直接在緩存中查詢到了結果,因爲第一個會話關閉了,而且開啓了二級緩存,所以將一級緩存中的內容保存到了二級緩存中,當我們查詢的時候,就可以直接在緩存中取數據了
記得將實體類序列化
public class User implements Serializable {
private int id;
...
}
總結
查詢的順序是:二級緩存 –> 一級緩存 –> 數據庫
先查詢二級緩存,如果命中,則直接返回給用戶,如果沒有命中,就查詢一級緩存;
如果一級緩存命中,則直接返回給用戶,如果沒有命中,就查詢數據庫。