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