写在前面:
学redis,还是得搭配SpringCache来玩一玩。
前置内容
学redis,还是得搭配SpringCache来玩一玩。
前置内容
- win安装+redis基础
- springboot使用redis
文章目录
- 导入依赖
- 配置cache
- 使用
- @Cacheable
- @CachePut
- @CacheEvict
- 配置过期时间
- 依据cacheName设置
- 在注解上截取过期时间
导入依赖
<!--redis依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--redis连接池 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><!--SpringCache缓存 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>
配置cache
在yml下
spring:cache:type: redisredis:key-prefix: Client_ #key前缀,如果配置了cacheManager则失效use-key-prefix: true #是否开启key前缀cache-null-values: true #是否缓存空值
在配置类上加上@EnableCaching开启缓存
配置序列化器
RedisConfig implements CachingConfigurer
redis的序列化器配置见前文,
/*** 对缓存进行序列化和反序列化的配置* @param factory redis连接工厂* @return*/@Beanpublic CacheManager cacheManager(RedisConnectionFactory factory){RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofDays(1)) // 配置缓存时长// 注意0为永久用于 Duration.ZERO 声明永久缓存。.prefixCacheNameWith("Client:") // 前缀.computePrefixWith(cacheName -> "caching:" + cacheName); //前缀动态.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string())) // key序列化方式.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json())); // value序列化方式return RedisCacheManager.builder(factory).cacheDefaults(config).build();}
使用
在这里配置就差不多了,在需要进行缓存操作的地方加注解就可以了
@Cacheable
该注解为缓存获取注解:
如果缓存中没有则进行查询在添加到缓存,如果缓存有则直接走缓存
属性
- value/cacheName
他们互为别名
确定目标高速缓存(或高速缓存),与特定 Bean 定义的限定符值或 Bean 名匹配
最终缓存的key为prefix+cacheName:: key - key
指定缓存的key,可以使用Spring Expression Language (SpEL) 表达式来进行动态设置。
SpEL 表达式:
- 可以使用 #root.method, #root.target, and #root.caches 来指定 方法, 目标对象和受影响的缓存的method引用
@cacheable(value =“phone”,key="#root.methodName”)
指定方法名来作为- 可以使用#形参名字来使用,下面是用phone的id来
@Cacheable(value = “Phone”,key=“#phone.id”)
public Result<List> getAll(Phone phone)- 方法参数可以通过索引访问。例如,可以通过 或 #p1 #a1访问#root.args[1]第二个参数。如果该信息可用,也可以按名称访问参数。
- cacheManager
指定管理器 - condition
缓存的条件,可以为空,使用SPEL表达式编写,返回true或者false,true表示存入缓存 - KeyGenerator
指定key生成对策
如果是自定义对象类型,判断不了可以自定义KeyGenerator
@Component
public class MyGenerator implements KeyGenerator{@overridepublic Object generate(object o, Method method, object... objects){}
}
- unless
用于否决缓存放置操作的 Spring 表达式语言 (SpEL) 表达式。如果条件的计算结果为 true。
默认值为 “”,表示缓存永远不会被否决。 - cacheResolver
要使用的自定义 org.springframework.cache.interceptor.CacheResolver 的 Bean 名称。
@CachePut
更新缓存
每次都会调用方法,把返回值缓存起来,每次都会更新/新增
注解和前面一样
@CacheEvict
删除缓存
调用后删除指定缓存
注解相同,多了几个
- allEntries
是否删除缓存中的所有条目。 - beforeInvocation
是否应在调用该方法之前进行逐出。
将此属性设置为 true,会导致逐出发生,而不考虑方法结果(即,是否引发异常)。
配置过期时间
我是2种方法都配置了的
依据cacheName设置
主要在与对于每一个cacheName设置不同的RedisCacheConfiguration
多个cacheName就加多个withCacheConfiguration就可以了
/*** 对缓存进行序列化和反序列化的配置** @param factory redis连接工厂* @return*/@Beanpublic CacheManager cacheManager(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory factory) {RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofDays(1)) // 配置缓存时长.prefixCacheNameWith("Client:") // 前缀.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string())) // key序列化方式.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json())); // value序列化方式// 如果不需要第二种就把CustomRedisCacheManager换成RedisCacheManagerreturn CustomRedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(factory).cacheDefaults(config).withCacheConfiguration("contact:relation", getCacheConfigurationWithTtl(redisTemplate, Duration.ofMinutes(30))).transactionAware().build();}RedisCacheConfiguration getCacheConfigurationWithTtl(RedisTemplate<String, Object> template, Duration time) {return RedisCacheConfiguration.defaultCacheConfig().prefixCacheNameWith("Client:") // 前缀// 设置key为String.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getStringSerializer()))// 设置value 为自动转Json的Object.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getValueSerializer()))// 不缓存null.disableCachingNullValues()// 缓存数据保存1小时.entryTtl(time);}
在注解上截取过期时间
在cacheName上面加上#时间就可以了
/*** 自定义缓存管理器*/
public class CustomRedisCacheManager extends RedisCacheManager {public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {super(cacheWriter, defaultCacheConfiguration);}/*** 针对@Cacheable设置缓存过期时间* @param name* @param cacheConfig* @return*/@Overrideprotected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {String[] array = StringUtils.delimitedListToStringArray(name, "#");// 解析TTLif (array.length > 2) {char c = array[1].charAt(array.length - 1);long ttl = Long.parseLong(StrUtil.sub(array[1], 0, array[1].length() - 1));cacheConfig = switch (c){case 's','S' -> cacheConfig.entryTtl(Duration.ofSeconds(ttl));case 'm','M' -> cacheConfig.entryTtl(Duration.ofMinutes(ttl));case 'h','H' -> cacheConfig.entryTtl(Duration.ofHours(ttl));case 'd','D' -> cacheConfig.entryTtl(Duration.ofDays(ttl));default -> cacheConfig.entryTtl(Duration.ofSeconds(Long.parseLong(array[1])));}cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl)); // 注意单位我此处用的是秒,而非毫秒}return super.createRedisCache(array[0], cacheConfig);}}