本文基于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
.GenericObjectPoolConfig at 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] ... 49 common frames omitted
在pom文件中引入下面的包
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</
artifactId> </dependency>
* 与Redis相关的POM依赖 <dependency> <groupId>org.springframework.boot</groupId> <
artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <
groupId>org.springframework.boot</groupId> <artifactId>
spring-boot-starter-data-redis</artifactId> </dependency>
* 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: 0 timeout: 10000
#redis 连接超时时间ms database: 0
* RedisCacheManager的配置
单独为不同的缓存可以配置不同的超时时间
disableCachingNullValues 不缓存空值
网上很多教程的配置是 RedisCacheConfiguration defaultCacheConfig =
RedisCacheConfiguration.defaultCacheConfig(); defaultCacheConfig.entryTtl
(Duration.ofSeconds(30L)); defaultCacheConfig.disableCachingNullValues();
这种配置是错误的 看完entryTtl和disableCachingNullValues的返回值均为RedisCacheConfiguration
所以上面的配置方法是无效的
下面是配置源码
@Bean CacheManager cacheManager(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(); return cacheManager; }
* 注解式的Redis处理
注解式的使用就是在方法上面加上Cacheable / CacheEvict / CachePut的注解
注解支持使用EL表达式 这里就是支持使用相关的参数和属性来表示
#root.targetClass 是类名
#p0是第一个参数值 @Cacheable(value = "test", key = "#root.targetClass + '_' + #p0 +
'_' + #p1")
到此使用简单的注解式的redis缓存配置就结束了
实际在项目中会遇到某些特殊的场景 某些缓存更希望用一个线程负责更新缓存 而不是单独的请求去判断 本文缓存更新采用了RedisTemplate手动写入的方式
5. RedisTemplate的配置
一开始使用的序列化方式不对 导致序列化出来的和上面系统自动缓存的不一致,导致上面读取缓存的时候总是值错误 在网上看了很多资料 后来看了源码
试了很多序列化方式 发现默认的是这个序列化类JdkSerializationRedisSerializer
在同时使用了上面注解的缓存和这种手动缓存的时候 特别需要注意的就是这个序列化方式的一致性 也可以改上面默认的序列化方式
@Bean public RedisTemplate<String, Integer>
redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Integer>
redisTemplate= new RedisTemplate<>(); redisTemplate.setKeySerializer(new
StringRedisSerializer()); redisTemplate.setValueSerializer(new
JdkSerializationRedisSerializer()); redisTemplate.setExposeConnection(true);
redisTemplate.setConnectionFactory(factory); redisTemplate.afterPropertiesSet();
return redisTemplate; }
* 使用RedisTemplate进行增删
封装一个类用于手动对缓存进行操作 还有其他操作 这个demo用不到就没有做 这里只有增加和删除两种操作 @Component public class
MyRedisCacheManager { @Autowiredprivate RedisTemplate redisTemplate; /*
插入数据或者更新数据 */ public void insert(String key, Object value, long timeout,
TimeUnit timeUnit) {if (StringUtils.isBlank(key) || !ObjectUtils.anyNotNull(
value)) { return; } if (timeout == 0) { redisTemplate.opsForValue().set(key,
value); } else { redisTemplate.opsForValue().set(key, value, timeout,
timeUnit); } }public void delete(String key) {
redisTemplate.opsForValue().getOperations().delete(key); } }
这里是整个项目的源码 可供参考GITHUB
<https://github.com/yingziisme/spring-boot-2.x-cache-redis-demo>
微信公众号不定时更新中
热门工具 换一换