前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot 2.x 使用Redis作为缓存 设置有效时间及自动更新策略

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

作者头像
yingzi_code
发布2019-08-31 13:42:54
7.8K0
发布2019-08-31 13:42:54
举报

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/yingziisme/article/details/81463391

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

由于在redis的客户端上采用了Letture 这里讲一下jedis和Letture的简单说明

  • Lettuce 和 Jedis 的定位都是Redis的client 都可以直接连接redis server
  • Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接
  • Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,应为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例

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

代码语言:javascript
复制
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文件中引入下面的包

代码语言:javascript
复制
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
  1. 与Redis相关的POM依赖
代码语言:javascript
复制
<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>
  1. Application里面的配置 这里使用的time-to-live是对所有redis缓存统一配置的时间 实际使用会有不方便的地方 可能不同的缓存需要不同的超时时间
代码语言:javascript
复制
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
  1. RedisCacheManager的配置 单独为不同的缓存可以配置不同的超时时间 disableCachingNullValues 不缓存空值 网上很多教程的配置是
代码语言:javascript
复制
        RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
        defaultCacheConfig.entryTtl(Duration
                .ofSeconds(30L));
        defaultCacheConfig.disableCachingNullValues();

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

代码语言:javascript
复制
@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;
    }
  1. 注解式的Redis处理 注解式的使用就是在方法上面加上Cacheable / CacheEvict / CachePut的注解 注解支持使用EL表达式 这里就是支持使用相关的参数和属性来表示 #root.targetClass 是类名 #p0是第一个参数值
代码语言:javascript
复制
@Cacheable(value = "test", key = "#root.targetClass + '_' + #p0 + '_' + #p1")

到此使用简单的注解式的redis缓存配置就结束了 实际在项目中会遇到某些特殊的场景 某些缓存更希望用一个线程负责更新缓存 而不是单独的请求去判断 本文缓存更新采用了RedisTemplate手动写入的方式 5. RedisTemplate的配置 一开始使用的序列化方式不对 导致序列化出来的和上面系统自动缓存的不一致,导致上面读取缓存的时候总是值错误 在网上看了很多资料 后来看了源码 试了很多序列化方式 发现默认的是这个序列化类JdkSerializationRedisSerializer 在同时使用了上面注解的缓存和这种手动缓存的时候 特别需要注意的就是这个序列化方式的一致性 也可以改上面默认的序列化方式

代码语言:javascript
复制
     @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;
    }
  1. 使用RedisTemplate进行增删 封装一个类用于手动对缓存进行操作 还有其他操作 这个demo用不到就没有做 这里只有增加和删除两种操作
代码语言:javascript
复制
@Component
public class MyRedisCacheManager {

    @Autowired
    private 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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年08月12日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档