使用Redis做Mybatis的二级缓存
文章目錄
- 前言
- 一、二級緩存
- 二、使用步驟
- 1.開啟二級緩存
- 2.編寫ApplicationContextHolder
- 3.編寫RedisCache二級緩存工具類
- 4.在mapper.xml文件中開啟全局二級緩存
- 5.配置RedisTemplate序列化工具類,實體也需要實現序列化接口
- 三、測試
- 總結
前言
本篇記錄怎么使用Redis做Mybtais的緩存。
一、二級緩存
MyBatis中的緩存分為一級緩存和二級緩存
- 一級緩存:基于sqlSession的緩存
- 二級緩存:基于多個sqlSession 共享的namspace數據塊
通常一個mapper 都一個namespace,所有的相關二級緩存都存在該namespace 數據塊下
查詢順序:先去二級緩存,如果二級沒有再去一級緩存,一級沒有再去數據庫
注意:在spring 配置的mybatis 中不存在一級緩存,二級緩存發生增刪改,該namespace 下所有緩存數據 立即清空,目的是為了避免有臟數據存在
二、使用步驟
創建項目,導入依賴和基本編碼部分不再贅述
1.開啟二級緩存
在配置文件yml中加入以下配置
代碼如下:
cache-enabled: true #使用緩存2.編寫ApplicationContextHolder
該類主要是為了在spring環境中獲取非spring容器管理的bean
package com.lzl.secondcache;import org.springframework.stereotype.Component; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.data.redis.core.RedisTemplate; /*** 在spring中,只要實現或者繼承xxAware接口或者類,在實例該對象時,* 會調用實現xxAware接口的類的方法,把參數傳遞*/ /*** --效率,是成功的核心關鍵--* 在spring中獲取非spring管理的bean對象* @Author lzl* @Date 2023/3/9 08:00*/ @Component public class ApplicationContextHolder implements ApplicationContextAware {//spring容器private static ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {ApplicationContextHolder.applicationContext = applicationContext;}public static RedisTemplate getRedisTemplate(){return ApplicationContextHolder.applicationContext.getBean("redisTemplate",RedisTemplate.class);} }3.編寫RedisCache二級緩存工具類
package com.lzl.secondcache; import org.apache.ibatis.cache.Cache; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.RedisSerializer;import java.util.Set; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;/*** 數據查詢順序:二級緩存 -> 一級緩存 -> 數據庫* 我們在mybatis中指定了二級緩存,在mybatis啟動會生成Cache對象,* 如果在該類使用@Autowired注入RedisTemplate是無法注入的,需要使用spring注入*/ /*** --效率,是成功的核心關鍵--** @Author lzl* @Date 2023/3/9 08:02*/public class RedisCache implements Cache{//RedisTemplate對象private RedisTemplate redisTemplate;//id相當于當前sql對應的cache的命名空間 namespace="com.qf.mapper.xxxMapper"private String id;//讀寫鎖:多線程中可以共享鎖,如果大家都是讀操作,提高數據的讀的并發能力//如果有一個人進行了寫操作,其他人都不能進行讀寫操作了private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();//獲取RedisTemplate對象public RedisTemplate getRedisTemplate(){//判斷if(redisTemplate == null){synchronized (RedisCache.class){if(redisTemplate == null){RedisTemplate redisTemplate = ApplicationContextHolder.getRedisTemplate();//設置key使用string類型的序列化方式redisTemplate.setKeySerializer(RedisSerializer.string());return redisTemplate;}return this.redisTemplate;}}return redisTemplate;}@Overridepublic ReadWriteLock getReadWriteLock() {return readWriteLock;}//構造器public RedisCache(String id) {System.out.println("id:"+id);this.id = id;}//id相當于當前sql對應的cache的命名空間@Overridepublic String getId() {System.out.println("getId:"+id);return id;}/*** 將結果放入緩存,當訪問查詢方法時調用,所以這里必須通過getRedisTemplate()方法來獲取redisTemplate對象* @param key -> 命名空間 + sql + 參數 = 組成的字符串* @param value -> sql查詢的結果*/@Overridepublic void putObject(Object key, Object value) {System.out.println("putObject中的key:"+key);System.out.println("putObject中的value:"+value);getRedisTemplate().opsForValue().set(key.toString(),value);}/*** 獲取緩存中的數據,當訪問查詢方法時調用,所以這里必須通過getRedisTemplate()方法來獲取redisTemplate對象* @param key* @return*/@Overridepublic Object getObject(Object key) {System.out.println("getObject:"+key);return getRedisTemplate().opsForValue().get(key.toString());}/*** 從緩存中移除數據,當訪問查詢方法時調用,所以這里必須通過getRedisTemplate()方法來獲取redisTemplate對象* @param key* @return*/@Overridepublic Object removeObject(Object key) {System.out.println("removeObject:"+key);return getRedisTemplate().delete(key.toString());}/*** 清空緩存*/@Overridepublic void clear() {System.out.println("clear");Set keys = getRedisTemplate().keys("*" + id + "*");System.out.println("清空緩存keys:"+keys);getRedisTemplate().delete(keys);}/*** 獲取緩存數據長度* @return*/@Overridepublic int getSize() {Set keys = getRedisTemplate().keys("*" + id + "*");return keys.size();}}4.在mapper.xml文件中開啟全局二級緩存
<!-- 開啟二級緩存(全局) --><!--type:使用自定義的對象進行存儲blocking:true 查詢時是否阻塞加鎖flushInterval: 毫秒值,緩存多久清空一次eviction: 緩存失效策略: LRU – 最近最少使用:移除最長時間不被使用的對象。FIFO – 先進先出:按對象進入緩存的順序來移除它們。SOFT – 軟引用:基于垃圾回收器狀態和軟引用規則移除對象。WEAK – 弱引用:更積極地基于垃圾收集器狀態和弱引用規則移除對象。readOnly:true 只讀,不能被修改size: 1024 緩存的大小--><cache type="com.lzl.secondcache.RedisCache"/>5.配置RedisTemplate序列化工具類,實體也需要實現序列化接口
package com.lzl.config;import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; /*** --效率,是成功的核心關鍵--** @Author lzl* @Date 2023/3/9 08:05*/ @Configuration public class RedisConfig {/*** springboot 默認幫我們創建的RedisTemplate的key和value的序列化方式是jdk默認的方式,* 我們有時候手動向redis中添加的數據可能無法被查詢解析出來,所以我們需要修改序列化方式* @param connectionFactory* @return*/@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();// 配置連接工廠redisTemplate.setConnectionFactory(connectionFactory);// 使用StringRedisSerializer來序列化和反序列化Redis的key值StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();// 使用Jackson2JsonRedisSerializer來序列化和反序列化Redis的value值Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);// 配置對象映射器ObjectMapper objectMapper = new ObjectMapper();// 指定要序列化的域,field,get和set,以及修飾符范圍。ANY指包括private和public修飾符范圍objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 指定序列化輸入類型,類的信息也將添加到json中,這樣才可以根據類名反序列化。objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);// 將對象映射器添加到序列化器中jackson2JsonRedisSerializer.setObjectMapper(objectMapper);// 配置key,value,hashKey,hashValue的序列化方式redisTemplate.setKeySerializer(stringRedisSerializer);redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);redisTemplate.setHashKeySerializer(stringRedisSerializer);redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);return redisTemplate;} }需要注意的是參數列表會報一個無法自動注入的錯誤,屬于正常現象,不影響代碼正常運行
實體類需要實現序列化接口如下圖所示
三、測試
首先我們先開啟Redis,這里開虛擬機太麻煩,我使用了windows版的redis
啟動成功
啟動項目
啟動成功,測試二級緩存的基本思路是,先調用查詢的方法,查看redis中是否有緩存數據,再調用刪除的方法,再次查看查看redis中的緩存數據是否被刪除
先執行查詢
查看控制臺
我這里之前已經查過一次,所以直接調用了緩存,沒有執行sql語句,如果是第一次訪問,會先執行sql語句,再建立緩存
執行刪除
查看控制臺
刪除成功!我們再次執行查詢
查看控制臺:
發現執行了sql語句
再次查詢
緩存命中!大功告成!
總結
本篇簡單記錄一下springboot整合mybatis使用redis做二級緩存
總結
以上是生活随笔為你收集整理的使用Redis做Mybatis的二级缓存的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux系统的相关介绍及VMware1
- 下一篇: linux cmake编译源码,linu