前言:乾貨記錄學習mybatis實際開發中快取的使用。

 	環境: springboot2.X  +  mybatis3.x

Mybatis是一款持久層框架,它提供了一級快取和二級快取。

名詞解釋

  • 一級快取(mybatis預設開啟)

    同一個sqlSession中有效,在同一個SqlSession中,執行兩次相同的sql查詢,第二次不走資料庫查詢,而是在快取中獲取。
  • 二級快取(需要開發者自行新增程式碼開啟)

    二級快取開啟後,不同的sqlSession獲取同一資料時,可以不走資料庫查詢直接從快取中獲取。

    快取原理:PerpetualCache 的 HashMap本地快取

二級快取的開啟

 <!--mybatise 配置檔案中設定-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!--某一個mapper中開啟,mapper 配置檔案中設定-->
<cache type="org.apache.ibatis.cache.impl.PerpetualCache" 具體執行快取操作的類,mybatis預設PerpetualCache,我們可以自定義修改
blocking="false" (是否使用阻塞快取): 預設為false,當指定為true時將採用BlockingCache進行封裝,使用BlockingCache會在查詢快取時鎖住對應的Key,如果快取命中了則會釋放對應的鎖,否則會在查詢資料庫以後再釋放鎖這樣可以阻止併發情況下多個執行緒同時查詢資料.
eviction="LUR" 回收策略 預設 LUR 最近最少使用
flushInterval="" 快取重新整理時間間隔,單位毫秒,不設定則在呼叫時重新整理
readOnly="true" 只讀
size="1024" 快取物件的個數 預設1024/>
<!-- 操作 CUD的 statement時候,會強制重新整理二級快取 -->
<!-- 我們可以指定 某一個 setect 操作 使用快取或者不使用快取 useCache 可以指定某一個 cud 操作 是否強制重新整理快取 flushCache -->

**注意:被快取的物件可以被序列化和反序列化,就是實現實現Serializable介面**

使用redis替換mybatis自身的快取實現(分散式快取)

//功能簡寫了,使用時根據自己實際情況修改
public class MyRedisCache implements Cache {
private final String id; //當前放入快取的Mapper的 namespace 名稱空間
private final Map<Object, Object> cache = new HashMap<>();
public MyRedisCache(String id) {
this.id = id;
}
// 返回cache的唯一標識
@Override
public String getId() {
return id;
}
// 快取放入值
// redis --- RedisTemplate StringRedisTemplate
@Override
public void putObject(Object key, Object value) {
getRedisTemplate().opsForHash().put(key,value);
}
// 從快取中獲取值
@Override
public Object getObject(Object key) {
return getRedisTemplate().opsForHash().get(key);
}
@Override
public void clear() {
//清空namespace
getRedisTemplate().delete(id.toString());//清空快取
}
...
}
<!--使自定義的快取執行類生效-->
<cache type="...MyRedisCache" .../>

自定義快取執行類時注意的問題

  • RedisTemplate物件是自動注入到IOC容器中,然後通過ApplicationContext物件回去容器物件。

    在SpringBoot內部提供介面 ApplicationContextAware 獲取IOC容器ApplicationContext物件。然後通過applicationContext物件獲取Redis操作物件 RedisTemplate 物件。
@Configuration
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
//工廠中獲取物件 工廠中RedisTemplate 預設 name redisTemplate
public static Object getBean(String beanName){
return applicationContext.getBean(beanName);
}
}
  • 通過檢視原始碼得到mybatis做快取時使用的是Map,那麼他的key的設計就很重要了,mybatis是使用mapper的 namespace 和sql做key,我們根據實際情況自己設計,存入redis的key的策略和合適的資料結構儲存值(redis的資料結構後續更新)。我使用的是hash結構,redisTemplate.opsForHash().put(namespace,key,value);

最後

感謝您的閱讀,各位大佬有什麼意見和問題歡迎評論區留言!

覺得文章對你有幫助記得給我點個贊,歡迎大家關注和轉發文章!