首頁 > 軟體

如何利用Redis作為Mybatis的二級快取

2022-08-11 14:03:05

前言

今天在開發時發現一個奇怪的問題,我手動改完資料庫竟然不生效,反覆確認環境無誤後猜測是快取的問題,因為是新接手的專案,程式碼還不熟悉,仔細一看,是開啟了二級快取,並且存入Redis。

那今天就聊聊怎麼優雅的用Redis作為Mybatis的二級快取。

要優雅就選擇Mybatis-Plus

關於Mybatis-Plus的基礎設定就不多做介紹了,只說和二級快取有關的。

首先在組態檔開啟二級快取。

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    cache-enabled: true   # 開啟二級快取
  mapper-locations: classpath:*/mapper/*.xml

Redis設定

這部分就是Redis的基本用法:

  redis:
    host: 101.411.160.111
    database: 0
    port: 6311
    password: 1111111

設定RedisTemplate

@Configuration
public class RedisConfig {
    /**
     * 設定系列化方式、事務等設定
     */
    @Bean
    public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory)
    {
        RedisTemplate<String,Serializable> redisTemplate = new RedisTemplate<>();
​
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        //設定key序列化方式string
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //設定value的序列化方式json
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
​
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
​
        redisTemplate.afterPropertiesSet();
​
        return redisTemplate;
    }
}

自定義Mybatis快取

我們只需要實現Cache這個介面。

@Slf4j
public class MybatisRedisCache implements Cache {
    private static final String COMMON_CACHE_KEY = "mybatis";
    // 讀寫鎖
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true)
    private final RedisTemplate<String, Object> redisTemplate;
    private final String nameSpace;
​
    public MybatisRedisCache(String nameSpace) {
        if (nameSpace == null) {
            throw new IllegalArgumentException("Cache instances require an ID");
        }
        redisTemplate = SpringUtil.getBean("redisTemplate");
        this.nameSpace = nameSpace;
    }
    @Override
    public String getId() {
        return this.nameSpace;
    }
​
    private String getKeys() {
​
        return COMMON_CACHE_KEY + "::" + nameSpace + "::*";
    }
​
    private String getKey(Object key) {
        return COMMON_CACHE_KEY + "::" + nameSpace + "::" + DigestUtils.md5Hex(String.valueOf(key));
    }
    @Override
    public void putObject(Object key, Object value) {
        redisTemplate.opsForValue().set(getKey(key), value, 10, TimeUnit.MINUTES);
    }
    @Override
    public Object getObject(Object key) {
        try {
            return redisTemplate.opsForValue().get(getKey(key));
        } catch (Exception e) {
            e.printStackTrace();
            log.error("快取出錯 ");
        }
        return null;
    }
​
    @Override
    public Object removeObject(Object o) {
        Object n = redisTemplate.opsForValue().get(getKey(o));
        redisTemplate.delete(getKey(o));
        return n;
    }
​
    @Override
    public void clear() {
        Set<String> keys = redisTemplate.keys(getKeys());
        if (CollectionUtil.isNotEmpty(keys)) {
            assert keys != null;
            redisTemplate.delete(keys);
        }
    }
    @Override
    public int getSize() {
        Set<String> keys = redisTemplate.keys(getKeys());
        if (CollectionUtil.isNotEmpty(keys)) {
            assert keys != null;
            return keys.size();
        }
        return 0;
    }
    @Override
    public ReadWriteLock getReadWriteLock() {
        return this.readWriteLock;
    }
}

測試

1.第一次查詢,走資料庫,並寫入快取。

看看Redis的記錄:

2.第二次查詢,直接走快取

3.重啟專案,依然可以直接查快取

快取命中率(Cache Hit Ratio)

不知道有沒有細心的同學注意到這樣一行紀錄檔:

Cache Hit Ratio [com.yitiao.mapper.ArticleMapper]: 0.5

最後這個0.5就是快取命中率,代表一共查詢兩次,命中一次快取一次。

一級快取和二級快取

一級快取

一級快取 Mybatis 的一級快取是指 SQLSession,一級快取的作用域是 SQlSession , Mabits 預設開啟一級快取。 在同一個SqlSession中,執行相同的SQL查詢時;第一次會去查詢資料庫,並寫在快取中,第二次會直接從快取中取。 當執行SQL時候兩次查詢中間發生了增刪改的操作,則SQLSession的快取會被清空。

每次查詢會先去快取中找,如果找不到,再去資料庫查詢,然後把結果寫到快取中。 Mybatis的內部快取使用一個HashMap,key為hashcode+statementId+sql語句。Value為查詢出來的結果集對映成的java物件。 SqlSession執行insert、update、delete等操作commit後會清空該SQLSession快取。

二級快取

二級快取 二級快取是 mapper 級別的,Mybatis預設是沒有開啟二級快取的。 第一次呼叫mapper下的SQL去查詢使用者的資訊,查詢到的資訊會存放到該 mapper 對應的二級快取區域。 第二次呼叫 namespace 下的 mapper 對映檔案中,相同的sql去查詢使用者資訊,會去對應的二級快取內取結果。

什麼時候該開啟二級快取

說實話,我遇到開啟二級快取的時候並不多,因為快取有利也有弊。

我的建議是如果發現介面耗時嚴重,可以線上上開啟二級快取,開發環境關掉,為什麼呢?

就拿今天我遇到的事來說,開發直接改庫不能立即生效,就很煩。

到此這篇關於如何利用Redis作為Mybatis的二級快取的文章就介紹到這了,更多相關Redis Mybatis二級快取內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com