SpringBoot 2.x 使用Redis作为缓存 设置有效时间及自动更新策略

本文基于Springboot2.0.4 数据库使用mysql

由于在redis的客户端上采用了Letture

这里讲一下jedis和Letture的简单说明

Lettuce 和 Jedis 的定位都是Redis的client 都可以直接连接redis server

Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接

Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,应为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例

所以一开始在启动程序的时候就遇到这个错误

Caused by: java.lang.ClassNotFoundException: org.apache.commons.pool2.impl.GenericObjectPoolConfigat java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_91] at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_91] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) ~[na:1.8.0_91] at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_91] ...49common frames omitted

在pom文件中引入下面的包

org.apache.commons

commons-pool2

与Redis相关的POM依赖

org.springframework.boot

spring-boot-starter-cache

org.springframework.boot

spring-boot-starter-data-redis

Application里面的配置

这里使用的time-to-live是对所有redis缓存统一配置的时间 实际使用会有不方便的地方 可能不同的缓存需要不同的超时时间

spring:

application:

name:redis-demo

cache:

type:redis

redis:

time-to-live:20000#缓存超时时间ms

cache-null-values:false#是否缓存空值

redis:

port:6379

host:localhost

lettuce:

pool:

max-active:8

max-wait:-1

max-idle:8

min-idle:

timeout:10000#redis 连接超时时间ms

database:

RedisCacheManager的配置

单独为不同的缓存可以配置不同的超时时间

disableCachingNullValues 不缓存空值

网上很多教程的配置是

RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();defaultCacheConfig.entryTtl(Duration.ofSeconds(30L));defaultCacheConfig.disableCachingNullValues()

这种配置是错误的 看完entryTtl和disableCachingNullValues的返回值均为RedisCacheConfiguration 所以上面的配置方法是无效的

下面是配置

@Bean

CacheManagercacheManager(RedisConnectionFactory connectionFactory) {

/* 默认配置, 默认超时时间为30s */

RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration

.ofSeconds(30L)).disableCachingNullValues();

/* 配置test的超时时间为120s*/

RedisCacheManager cacheManager = RedisCacheManager.builder(RedisCacheWriter.lockingRedisCacheWriter

(connectionFactory)).cacheDefaults(defaultCacheConfig).withInitialCacheConfigurations(singletonMap

("test",RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(120L))

.disableCachingNullValues())).transactionAware().build();

returncacheManager;

}

注解式的Redis处理

注解式的使用就是在方法上面加上Cacheable / CacheEvict / CachePut的注解

注解支持使用EL表达式 这里就是支持使用相关的参数和属性来表示

#root.targetClass 是类名

#p0是第一个参数值

@Cacheable(value="test",key="#root.targetClass+ '_' + #p0 + '_' + #p1")

到此使用简单的注解式的redis缓存配置就结束了

实际在项目中会遇到某些特殊的场景 某些缓存更希望用一个线程负责更新缓存 而不是单独的请求去判断 本文缓存更新采用了RedisTemplate手动写入的方式

RedisTemplate的配置

一开始使用的序列化方式不对 导致序列化出来的和上面系统自动缓存的不一致 导致上面读取缓存的时候总是值错误 在网上看了很多资料 后来看了源码 试了很多序列化方式 发现默认的是这个序列化类JdkSerializationRedisSerializer

在同时使用了上面注解的缓存和这种手动缓存的时候特别需要注意的就是这个序列化方式的一致性也可以改上面默认的序列化方式

@Bean

publicRedisTemplateredisTemplate(RedisConnectionFactory factory) {

RedisTemplate redisTemplate =newRedisTemplate();

redisTemplate.setKeySerializer(newStringRedisSerializer());

redisTemplate.setValueSerializer(newJdkSerializationRedisSerializer());

redisTemplate.setExposeConnection(true);

redisTemplate.setConnectionFactory(factory);

redisTemplate.afterPropertiesSet();

returnredisTemplate;

}

使用RedisTemplate进行增删

封装一个类用于手动对缓存进行操作 还有其他操作 这个demo用不到就没有做 这里只有增加和删除两种操作

@Component

public classMyRedisCacheManager {

@Autowired

privateRedisTemplateredisTemplate;

/* 插入数据或者更新数据 */

public voidinsert(String key,Object value, longtimeout,TimeUnit timeUnit) {

if(StringUtils.isBlank(key) || !ObjectUtils.anyNotNull(value)) {

return;

}

if(timeout ==) {

redisTemplate.opsForValue().set(key,value);

}else{

redisTemplate.opsForValue().set(key,value,timeout,timeUnit);

}

}

public voiddelete(String key) {

redisTemplate.opsForValue().getOperations().delete(key);

}

}

这里是整个项目的源码 可供参考

https://github.com/yingziisme/spring-boot-2.x-cache-redis-demo

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180812G0HA5O00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券