spring缓存注解@Cacheable和@CacheEvict,设置过期时间和批量模糊删除
spring缓存注解@Cacheable和@CacheEvict,设置过期时间和批量模糊删除
- 配置
- CacheManager 类
- key前缀配置
- RedisCache配置
- RedisCache
- 模糊匹配删除缓存
- @Cacheable
- @CacheEvict
配置
CacheManager 类
直接上代码
key前缀配置
spring-data-redis高版本的话, 直接在yaml配置即可,但是我的是2.1.18,不知道为什么没生效,看了下两个版本设置前缀的方法也不一样,应该是版本问题。
或者直接在配置类中设置,如下配置computePrefixWith() 如果有问题,打断点看RedisCache的createCacheKey方法
spring:cache:redis:key-prefix: xxx
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.CacheKeyPrefix;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import java.time.Duration;
import java.time.temporal.ChronoUnit;@Configuration
public class CacheConfig {/*** 最终调用 org.springframework.data.redis.cache.RedisCacheConfiguration#getKeyPrefixFor(java.lang.String)*/private static final CacheKeyPrefix DEFAULT_CACHE_KEY_PREFIX = cacheName -> "edu:service_spring:"+cacheName+":";@Beanpublic CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {ObjectMapper om = new ObjectMapper();RedisSerializer redisSerializer = new StringRedisSerializer();Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);// 解决查询缓存转换异常的问题om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);//非null才序列化om.setDefaultPropertyInclusion(JsonInclude.Include.NON_NULL);jackson2JsonRedisSerializer.setObjectMapper(om);// 配置序列化(解决乱码的问题)RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().computePrefixWith(DEFAULT_CACHE_KEY_PREFIX).entryTtl(Duration.of(1, ChronoUnit.DAYS)).serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);return new RedisConfigCacheManager(cacheWriter, redisConnectionFactory,config);}}
RedisCache配置
RedisCache不能针对具体每个key进行配置过期时间, 所以改造. 通过@Cacheable里的value, 分割#号后面的作为过期时间
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;import java.time.Duration;/*** redis 配置类*/
@Slf4j
public class RedisConfigCacheManager extends RedisCacheManager {private final RedisConnectionFactory redisConnectionFactory;private final RedisCacheWriter redisCacheWriter;public RedisConfigCacheManager(RedisCacheWriter cacheWriter,RedisConnectionFactory redisConnectionFactory,RedisCacheConfiguration defaultCacheConfiguration) {super(cacheWriter, defaultCacheConfiguration);this.redisConnectionFactory = redisConnectionFactory;this.redisCacheWriter = cacheWriter;}@Overrideprotected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {final int lastIndexOf = StringUtils.lastIndexOf(name, '#');if (lastIndexOf > -1) {final String ttl = StringUtils.substring(name, lastIndexOf + 1);final Duration duration = Duration.ofSeconds(Long.parseLong(ttl));cacheConfig = cacheConfig.entryTtl(duration);//修改缓存key和value值的序列化方式final String cacheName = StringUtils.substring(name, 0, lastIndexOf);return new CustomizedRedisCache(cacheName,this.redisCacheWriter,this.redisConnectionFactory, cacheConfig);}else{return new CustomizedRedisCache(name,this.redisCacheWriter,this.redisConnectionFactory, cacheConfig);}}}
RedisCache
模糊匹配删除缓存
@CacheEvict需要注意几点:
- 默认是不能模糊匹配的, @CacheEvict最终调用的就是RedisCache的evict方法,所以我们重写这个方法
- 批量清楚RedisCache采用的是keys命令匹配, 一般这个命令生产不能用, 换成scan
- evict方法入参的key就是@CacheEvict的key, 不是完整的redisKey, 需要调用createCacheKey来获得完整 的key
- @CacheEvict的key,不能直接写*号, 因为会解析el表达式报错, 要加上单引号
import org.springframework.core.convert.ConversionService;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;public class CustomizedRedisCache extends RedisCache {private static final String WILD_CARD = "*";private final String name;private final RedisCacheWriter cacheWriter;private final ConversionService conversionService;private final RedisConnectionFactory redisConnectionFactory;protected CustomizedRedisCache(String name, RedisCacheWriter cacheWriter, RedisConnectionFactory connectionFactory, RedisCacheConfiguration cacheConfig) {super(name, cacheWriter, cacheConfig);this.name = name;this.cacheWriter = cacheWriter;this.conversionService = cacheConfig.getConversionService();this.redisConnectionFactory = connectionFactory;}/*** 重写evict失效方法,即@CacleEvict注解调用的* @param key the key whose mapping is to be removed from the cache*/@Overridepublic void evict(Object key) {if (key instanceof String) {String keyString = key.toString();if (keyString.endsWith(WILD_CARD)) {//转化为真正的rediskey,即加上前缀String cacheKey = super.createCacheKey(key);evictLikeSuffix(cacheKey);return;}}super.evict(key);}/*** 后缀匹配** @param key*/public void evictLikeSuffix(String key) {//用scan替代keysRedisConnection connection = null;try {connection = this.redisConnectionFactory.getConnection();Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder().match(key).count(200).build());while (cursor.hasNext()) {connection.del(cursor.next());}} finally {if (connection != null) {connection.close();}}}
@Cacheable
最终完整的key是
zgd:service_spring:queryHotCoursesV3:xxxx(dto序列化string)
@Cacheable(value = "queryHotCoursesV3#3600", condition ="#dto.startPage <= 5 and #dto.pageSize <= 20 " +"and (#dto.keyWords == null or #dto.keyWords == '')")public PageVO<CoursesVO> queryHotCoursesV3(CoursePageParamReq dto) {}
@CacheEvict
@Override//key不能直接用星号,要加单引号。 否则Problem parsing left operand@CacheEvict(value = {"queryHotCoursesV3","findHotCoursesTempV2"},key = "'*'")public void flushCache() {mystudyMapper.flushCache();}
spring缓存注解@Cacheable和@CacheEvict,设置过期时间和批量模糊删除相关推荐
- Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用
从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...
- 详解Spring缓存注解@Cacheable,@CachePut , @CacheEvict使用
注释介绍 @Cacheable @Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存 @Cacheable 作用和配置方法 参数 解释 example value 缓 ...
- cacheable更新_详解Spring缓存注解@Cacheable,@CachePut , @CacheEvict使用
注释介绍 @Cacheable @Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存 @Cacheable 作用和配置方法 参数 解释 example value 缓 ...
- 三十七、缓存注解@Cacheable、@CacheEvict、@CachePut详解
# 缓存注解@Cacheable.@CacheEvict.@CachePut详解 ##一.@Cacheable用法详解 ###1.用在哪里? 用在方法或者类上. ###2.这两种 ...
- Spring 缓存注解@Cacheable 在缓存时候 ,出现了第一次进入调用 方法 ,第二次不调用的异常
Spring 缓存注解@Cacheable 在缓存时候 ,出现了第一次进入调用 方法 ,第二次不调用的异常 参考文章: (1)Spring 缓存注解@Cacheable 在缓存时候 ,出现了第一次进入 ...
- Redis 笔记(03)— string类型(设置key、获取key、设置过期时间、批量设置获取key、对key进行加减、对key值进行追加、获取value子串)
字符串 string 是 Redis 最简单的数据结构.Redis 所有的数据结构都是以唯一的 key 字符串作为名称,然后通过这个唯一 key 值来获取相应的 value 数据.不同类型的数据结构的 ...
- 2021-10-12Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用
从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...
- cacheable 表达式_Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用
从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...
- cacheable 表达式_Spring Boot缓存注解@Cacheable、@CacheEvict、@CachePut使用
从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...
最新文章
- 使用docker-compose进行多节点部署
- APC UPS网络管理卡 (AP9606/9617/9618/9619)的快速安装及配置指南
- C语音的预处理,编译,汇编,链接过程分析
- solaris 10 安装Apache Mysql PHP
- [翻译] NumSharp的数组切片功能 [:]
- Redis实现之对象(三)
- struts单例模式 java_Java单例设计模式详细介绍
- python 表白程序代码_python抖音表白程序源代码
- java jdk的作用_Java JDK环境配置及配置作用说明
- 微软2011 GCR MVP Open Day 之旅!
- loj2683「BalticOI 2013」非回文数 Palindrome-Free Numbers
- day11--Matplotlib--柱形图与盒图
- java 编程英语单词,语句
- 无法启动计算机上的服务msdtc,MSDTC服务无法启动,导致网站打不开
- 计算机设计大赛作品——冬奥可视化
- Filebeat log @timestamp处理
- C5750X7R2E105K230KA(电容器)MSP430F5249IRGCR微控制器资料
- 如何测量多个变量之间的非线性关系
- 骑行318、 2016.7.23
- oracle中varchar2类型的字段长度单位默认是按照byte来定义