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需要注意几点:

  1. 默认是不能模糊匹配的, @CacheEvict最终调用的就是RedisCache的evict方法,所以我们重写这个方法
  2. 批量清楚RedisCache采用的是keys命令匹配, 一般这个命令生产不能用, 换成scan
  3. evict方法入参的key就是@CacheEvict的key, 不是完整的redisKey, 需要调用createCacheKey来获得完整 的key
  4. @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,设置过期时间和批量模糊删除相关推荐

  1. Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用

    从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...

  2. 详解Spring缓存注解@Cacheable,@CachePut , @CacheEvict使用

    注释介绍 @Cacheable @Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存 @Cacheable 作用和配置方法 参数 解释 example value 缓 ...

  3. cacheable更新_详解Spring缓存注解@Cacheable,@CachePut , @CacheEvict使用

    注释介绍 @Cacheable @Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存 @Cacheable 作用和配置方法 参数 解释 example value 缓 ...

  4. 三十七、缓存注解@Cacheable、@CacheEvict、@CachePut详解

    #        缓存注解@Cacheable.@CacheEvict.@CachePut详解 ##一.@Cacheable用法详解 ###1.用在哪里?     用在方法或者类上. ###2.这两种 ...

  5. Spring 缓存注解@Cacheable 在缓存时候 ,出现了第一次进入调用 方法 ,第二次不调用的异常

    Spring 缓存注解@Cacheable 在缓存时候 ,出现了第一次进入调用 方法 ,第二次不调用的异常 参考文章: (1)Spring 缓存注解@Cacheable 在缓存时候 ,出现了第一次进入 ...

  6. Redis 笔记(03)— string类型(设置key、获取key、设置过期时间、批量设置获取key、对key进行加减、对key值进行追加、获取value子串)

    字符串 string 是 Redis 最简单的数据结构.Redis 所有的数据结构都是以唯一的 key 字符串作为名称,然后通过这个唯一 key 值来获取相应的 value 数据.不同类型的数据结构的 ...

  7. 2021-10-12Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用

    从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...

  8. cacheable 表达式_Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用

    从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...

  9. cacheable 表达式_Spring Boot缓存注解@Cacheable、@CacheEvict、@CachePut使用

    从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...

最新文章

  1. 使用docker-compose进行多节点部署
  2. APC UPS网络管理卡 (AP9606/9617/9618/9619)的快速安装及配置指南
  3. C语音的预处理,编译,汇编,链接过程分析
  4. solaris 10 安装Apache Mysql PHP
  5. [翻译] NumSharp的数组切片功能 [:]
  6. Redis实现之对象(三)
  7. struts单例模式 java_Java单例设计模式详细介绍
  8. python 表白程序代码_python抖音表白程序源代码
  9. java jdk的作用_Java JDK环境配置及配置作用说明
  10. 微软2011 GCR MVP Open Day 之旅!
  11. loj2683「BalticOI 2013」非回文数 Palindrome-Free Numbers
  12. day11--Matplotlib--柱形图与盒图
  13. java 编程英语单词,语句
  14. 无法启动计算机上的服务msdtc,MSDTC服务无法启动,导致网站打不开
  15. 计算机设计大赛作品——冬奥可视化
  16. Filebeat log @timestamp处理
  17. C5750X7R2E105K230KA(电容器)MSP430F5249IRGCR微控制器资料
  18. 如何测量多个变量之间的非线性关系
  19. 骑行318、 2016.7.23
  20. oracle中varchar2类型的字段长度单位默认是按照byte来定义

热门文章

  1. 吹了一个多月的联想Z5竟然是低端机,指望靠这个崛起就是痴人说梦
  2. Java 无意识自动装箱严重消耗性能
  3. excel如何批量删除缺失数据所在的行?
  4. Linux磁盘空间爆满怎么办?定时文件清理脚本配置实现
  5. 当提示“当前帐户被锁定,可能无法登录”时,如何解锁帐户?
  6. 电路设计软件详谈,基于电路设计软件protel实现脉冲电路仿真
  7. PHP教程:PHP开发快速入门_v20200418
  8. 鲲鹏与江西才俊的七夕之约
  9. 内网直播局域网直播校园直播播控系统如何建设
  10. 来公司必须了解的编码开发规范