本文基于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
领取专属 10元无门槛券
私享最新 技术干货