Spring cache整合Redis,并给它一个过期时间!

Stella981
• 阅读 1056

小Hub领读:

不知道你们有没给cache设置过过期时间,来试试?


上一篇文章中,我们使用springboot集成了redis,并使用RedisTemplate来操作缓存数据,可以灵活使用。

今天我们要讲的是Spring为我们提供的缓存注解Spring Cache。Spring支持多种缓存技术:RedisCacheManager、EhCacheCacheManager、GuavaCacheManager等,使用之前需要配置一个CacheManager的Bean。

配置好之后使用常用的三个注解来缓存数据:

  • @Cacheable
  • @CachePut
  • @CacheEvict。

这三个注解方别代表着什么意思,等会我们一一来解剖。

1、配置RedisCacheManager

刚才说了,首先我们需要配置一个缓存管理器,然后才能使用缓存注解来管理缓存。上一篇文章中我们已经整合了redis,接下来,我们只需要直接去配置RedisCacheManager即可。

  • com.markerhub.config.RedisConfig

    /**

    • 配置一个CacheManager才能使用@Cacheable等注解
    • 公众号:MarkerHub

    */ @Bean public CacheManager cacheManager(RedisTemplate<string, object> template) {

    // 基本配置
    RedisCacheConfiguration defaultCacheConfiguration =
            RedisCacheConfiguration
                    .defaultCacheConfig()
                    // 设置key为String
                    .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getStringSerializer()))
                    // 设置value 为自动转Json的Object
                    .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getValueSerializer()))
                    // 不缓存null
                    .disableCachingNullValues()
                    // 缓存数据保存1小时
                    .entryTtl(Duration.ofHours(1));
    
    // 够着一个redis缓存管理器
    RedisCacheManager redisCacheManager =
            RedisCacheManager.RedisCacheManagerBuilder
                    // Redis 连接工厂
                    .fromConnectionFactory(template.getConnectionFactory())
                    // 缓存配置
                    .cacheDefaults(defaultCacheConfiguration)
                    // 配置同步修改或删除 put/evict
                    .transactionAware()
                    .build();
    
    return redisCacheManager;
    

    }

上面的配置中,大部分代码都给出了注释,我们只需要根据需求配置一下即可。其中反序列策略延用了原来RedisTemplate的参数。

  • RedisCacheConfiguration
  • RedisCacheManager

还有一个重要的步骤不能忘记了,需要开启Spring Cache的缓存功能支持,很简单,只需要在RedisConfig上添加一个注解:

@EnableCaching

写一个例子

上面我们已经已经配置了RedisCacheManager帮我们管理缓存,接下来我们就去使用Spring Cache的注解来完成我们的代码测试。

下面的例子我写得可能有点粗,如果你对一些参数还不了解,建议你看看这篇文章: https://blog.csdn.net/dreamhai/article/details/80642010

1、@Cacheable

标记在方法或者类上,标识该方法或类支持缓存。Spring调用注解标识方法后会将返回值缓存到redis,以保证下次同条件调用该方法时直接从缓存中获取返回值。这样就不需要再重新执行该方法的业务处理过程,提高效率。

@Cacheable常用的三个参数如下:

  • cacheNames 缓存名称

  • key 缓存的key,需要注意key的写法哈

  • condition 缓存执行的条件,返回true时候执行

    @Slf4j @Service public class UserServiceImpl implements UserService {

    @Override
    @Cacheable(cacheNames = "cache_user", key="'user_' + #id")
    public User getById(long id) {
    
        log.info("进来查库了---------&gt;{}", id);
    
        User user = new User();
        user.setId(1L);
        user.setUsername("MarkerHub" + id);
        return user;
    }
    

    }

然后写一个具体的调用:

@RestController
public class UserController {

    @Autowired
    UserService userService;

    @GetMapping("/u/{id}")
    public User index(@PathVariable("id") Long id) {

        User user = userService.getById(id);
        return user;

    }
}

测试下访问结果,访问链接:http://localhost:8080/u/12

第一次调用时候控制台输出:

进来查库了---------&gt;12

第二次再访问的时候,就没有再输出,说明没有进入业务方法,就是在redis中获取结果直接返回。

看一下redis的可视化工具:

Spring cache整合Redis,并给它一个过期时间!

这里大家需要注意一下,在配置redis的序列化方式的时候,一定要配置下面的代码,这个在之前Springboot配置redis中已经说过了。

Jackson2JsonRedisSerializer<object> serializer = new Jackson2JsonRedisSerializer<object>(Object.class);

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(objectMapper);

如果你序列化之后的value只是一个简单的json数据,这样会引起强转错误的。需要注意一下!

2、@CacheEvict

标记在方法上,方法执行完毕之后根据条件或key删除对应的缓存。常用的属性:

  • allEntries boolean类型,表示是否需要清除缓存中的所有元素

  • key 需要删除的缓存的key

    @Override @CacheEvict(cacheNames = "cache_user", allEntries = true) public void update(User user) {

    // 更新逻辑...
    

    }

于是,update方法执行之后,cacheNames="cache_user"里面的所有缓存都会被删除!这也是很常用的方法。当然了,你还可以这样写,根据key来删除某个指定缓存:

@Override
@CacheEvict(cacheNames = "cache_user", key = "'user_' + #user.id")
public void update(User user) {

    // 更新逻辑...
}

3、@@CachePut

标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。

4、@Caching

可以在一个注解上标注多种注解,其拥有三个属性:cacheable、put和evict,分别用于指定@Cacheable、@CachePut和@CacheEvict

过期时间

我们已经实现了Spring Cache的基本功能,整合了Redis作为RedisCacheManger,但众所周知,我们在使用@Cacheable注解的时候是无法给缓存这是过期时间的。但有时候在一些场景中我们的确需要给缓存一个过期时间!

在缓存与库数据不一致的时候,自动过期就显得尤为重要,这是一个保底的方式。那么,如何给Spring cache一个过期时间呢?

其实不需要我们去整合第三方的包,比如Redission等,我们在配置RedisCacheManager的时候其实就可以配置过期时间,只是,这个过期时间是针对cache的。

这是什么意思?比如你使用了如下注解:

@Cacheable(cacheNames = "cache_user", key="'user_' + #id")

我们可以在初始化的时候指定cacheNames为cache_user的cache的过期时间。我们先来回顾一下RedisCacheManager的初始化配置。

Spring cache整合Redis,并给它一个过期时间!

上面在RedisCacheConfiguration上我们配置一个关于过期时间的配置.entryTtl(Duration.ofHours(1)),缓存数据保存一个小时。并且在RedisCacheManager上通过.cacheDefaults(defaultCacheConfiguration)进行了配置。这两行代码其实是在说,所有的缓存数据默认保存一个小时。

相比于以前,我们统一配置了缓存的过期时间是1个小时。但这还是写得比较固定,一般来说,我们想给不同的cache不同的过期时间,比如cache_postcache_user不一样的过期时间,那么这个怎么弄呢?能否在配置中实现吗?

答案是可以的,很简单,在RedisCacheManager中有这个方法:

RedisCacheManagerBuilder withCacheConfiguration(String cacheName, RedisCacheConfiguration cacheConfiguration)

可以给每个cacheName不同的RedisCacheConfiguration,之前的配置,我们是配置了一个默认的缓存配置,有个这个方法之后,我们就可以指定某个cache的缓存配置。每个缓存配置的不同的地方其实就是过期时间。因此,我们抽个方法出来生成缓存配置,代码如下:

RedisCacheConfiguration getCacheConfigurationWithTtl(RedisTemplate<string, object> template, long seconds) {

    return RedisCacheConfiguration
            .defaultCacheConfig()
            // 设置key为String
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getStringSerializer()))
            // 设置value 为自动转Json的Object
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getValueSerializer()))
            // 不缓存null
            .disableCachingNullValues()
            // 缓存数据保存1小时
            .entryTtl(Duration.ofSeconds(seconds));
}

参数seconds指定缓存的过期时间,因此,我们在RedisCacheManager中应该这样配置:

RedisCacheManager redisCacheManager =
        RedisCacheManager.RedisCacheManagerBuilder
                // Redis 连接工厂
                .fromConnectionFactory(template.getConnectionFactory())
                .cacheDefaults(getCacheConfigurationWithTtl(template, 60 * 60))
                .withCacheConfiguration("cache_user", getCacheConfigurationWithTtl(template, 60))
                .withCacheConfiguration("cache_post", getCacheConfigurationWithTtl(template, 120))
                // 配置同步修改或删除 put/evict
                .transactionAware()
                .build();

return redisCacheManager;
}

根据上面的配置,我们指定了cacheName如下:

  • cache_user过期时间为60秒
  • cache_post过期时间为120秒
  • 其他默认过期时间为1小时

这也是我建议大家的写法!

很多人还有其他实现写法,比如在cacheNames后面添加#3600,截取#后面的数字作为过期时间。

@Cacheable(cacheNames = "cache_user#3600", key="'user_' + #id")

更有一些人想给key一个过期时间,于是又有这种写法:

@Cacheable(cacheNames = "cache_user#3600", key="'user_' + #id + '#3600'")

其实在我看来没有必要。直接在配置中写好,简单方便!

结束语

好啦,今天的文章到此结束啦,右下角点个在看再走呗,哈哈。


推荐阅读:

分享一套SpringBoot开发博客系统源码,以及完整开发文档!速度保存!

Github上最值得学习的100个Java开源项目,涵盖各种技术栈!

2020年最新的常问企业面试题大全以及答案</string,></string,>

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Souleigh ✨ Souleigh ✨
2年前
前端性能优化 - 雅虎军规
无论是在工作中,还是在面试中,web前端性能的优化都是很重要的,那么我们进行优化需要从哪些方面入手呢?可以遵循雅虎的前端优化35条军规,这样对于优化有一个比较清晰的方向.35条军规1.尽量减少HTTP请求个数——须权衡2.使用CDN(内容分发网络)3.为文件头指定Expires或CacheControl,使内容具有缓存性。4.避免空的
Stella981 Stella981
2年前
SpringBoot集成redis + spring cache
SpringCache集成redis的运行原理:Spring缓存抽象模块通过CacheManager来创建、管理实际缓存组件,当SpringBoot应用程序引入springbootstarterdataredi依赖后吗,容器中将注册的是CacheManager实例RedisCacheManager对象,RedisCacheManager来负责创
Easter79 Easter79
2年前
SpringBoot集成redis + spring cache
SpringCache集成redis的运行原理:Spring缓存抽象模块通过CacheManager来创建、管理实际缓存组件,当SpringBoot应用程序引入springbootstarterdataredi依赖后吗,容器中将注册的是CacheManager实例RedisCacheManager对象,RedisCacheManager来负责创
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Easter79 Easter79
2年前
SpringBoot使用RedisTemplate操作Redis时,key值出现 -xac-xed-x00-x05t-x00-tb
原因分析原因与RedisTemplate源码中的默认序列化方式有关defaultSerializernewJdkSerializationRedisSerializer(classLoader!null?classLoader:this.getClass().getClassLoader()
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这