Spring缓存注解@Cacheable @CacheEvit @CachePut使用介绍

网友投稿 650 2022-12-31

Spring缓存注解@Cacheable @CacheEvit @CachePut使用介绍

Spring缓存注解@Cacheable @CacheEvit @CachePut使用介绍

目录I. 项目环境1. 项目依赖II. 缓存注解介绍1. @Cacheable2. @CachePut3. @CacheEvict4. @Caching5. 异常时,缓存会怎样?6. 测试用例7. 小结III. 不能错过的源码和相关知识点0. 项目

Spring在3.1版本,就提供了一条基于注解的缓存策略,实际使用起来还是很丝滑的,本文将针对几个常用的注解进行简单的介绍说明,有需要的小伙伴可以尝试一下

本文主要知识点:

@Cacheable: 缓存存在,则使用缓存;不存在,则执行方法,并将结果塞入缓存

@CacheEvit: 失效缓存

@CachePut: 更新缓存

I. 项目环境

1. 项目依赖

本项目借助SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA + redis5.0进行开发

开一个web服务用于测试

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-data-redis

全程使用默认配置,redis本机,端口6379,无密码

II. 缓存注解介绍

1. @Cacheable

这个注解用于修饰方法or类,当我们访问它修饰的方法时,优先从缓存中获取,若缓存中存在,则直接获取缓存的值;缓存不存在时,执行方法,并将结果写入缓存

这个注解,有两个比较核心的设置

/**

* 与 cacheNames 效果等价

*/

@AliasFor("cacheNames")

String[] value() default {};

@AliasFor("value")

aMBmUsK String[] cacheNames() default {};

/**

* 缓存key

*/

String key() default "";

cacheNames可以理解为缓存key的前缀,可以为组件缓存的key变量;当key不设置时,使用方法参数来初始化,注意key为SpEL表达式,因此如果要写字符串时,用单引号括起来

一个简单的使用姿势

/**

* 首先从缓存中查,查到之后,直接返回缓存数据;否则执行方法,并将结果缓存

*

* redisKey: cacheNames + key 组合而成 --> 支持SpEL

* redisValue: 返回结果

*

* @param name

* @return

*/

@Cacheable(cacheNames = "say", key = "'p_'+ #name")

public String sayHello(String name) {

return "hello+" + name + "-->" + UUID.randomUUID().toString();

}

如我们传参为 yihuihui, 那么缓存key为 say::p_yihuihui

除了上面三个配置值之外,查看@Cacheable注解源码的童鞋可以看到还有condition设置,这个表示当它设置的条件达成时,才写入缓存

/**

* 满足condition条件的才写入缓存

*

* @param age

* @return

*/

@Cacheable(cacheNames = "condition", key = "#age", condition = "#age % 2 == 0")

public String setByCondition(int age) {

return "condition:" + age + "-->" + UUID.randomUUID().toString();

}

上面这个case中,age为偶数的时候,才走缓存;否则不写缓存

接下来是unless参数,从名字上可以看出它表示不满足条件时才写入缓存

/**

* unless, 不满足条件才写入缓存

*

* @param age

* @return

*/

@Cacheable(cacheNames = "unless", key = "#age", unless = "#age % 2 == 0")

public String setUnless(int age) {

return "unless:" + age + "-->" + UUID.randomUUID().toString();

}

2. @CachePut

不管缓存有没有,都将方法的返回结果写入缓存;适用于缓存更新

/**

* 不管缓存有没有,都写入缓存

*

* @param age

* @return

*/

@CachePut(cacheNames = "t4", key = "#age")

public String cachePut(int age) {

return "t4:" + age + "-->" + UUID.randomUUID().toString();

}

3. @CacheEvict

这个就是我们理解的删除缓存

/**

* 失效缓存

*

* @param name

* @return

*/

@CacheEvict(cacheNames = "say", key = "'p_'+ #name")

public String evict(String name) {

return "evict+" + name + "-->" + UUID.randomUUID().toString();

}

4. @Caching

在实际的工作中,经常会遇到一个数据变动,更新多个缓存的场景,对于这个场景,可以通过@Caching来实现

/**

* caching实现组合,添加缓存,并失效其他的缓存

*

* @param age

* @return

*/

@Caching(cacheable = @Cacheable(cacheNames = "caching", key = "#age"), evict = @CacheEvict(cacheNames = "t4", key = "#age"))

public String caching(int age) {

return "caching: " + age + "-->" + UUID.randomUUID().toString();

}

上面这个就是组合操作

从 caching::age缓存取数据,不存在时执行方法并写入缓存;

失效缓存 t4::age

5. 异常时,缓存会怎样?

上面的几个case,都是正常的场景,当方法抛出异常时,这个缓存表现会怎样?

/**

* 用于测试异常时,是否会写入缓存

*

* @param age

* @return

*/

@Cacheable(cacheNames = "exception", key = "#age")

@Cacheable(cacheNames = "say", key = "'p_yihuihui'")

public int exception(int age) {

return 10 / age;

}

根据实测结果,当age==0时,上面两个缓存都不会成功

6. 测试用例

接下来验证下缓存注解与上面描述的是否一致

@RestController

public class IndexRest {

@Autowired

private BasicDemo helloService;

@GetMapping(path = {"", "/"})

public String hello(String name) {

return helloService.sayHello(name);

}

}

上面这个主要是验证@Cacheablehttp://注解,若缓存不命中,每次返回的结果应该都不一样,然而实际访问时,会发现返回的都是相同的

curl http://localhost:8080/?name=yihuihui

失效缓存

@GetMapping(path = "evict")

public String evict(String name) {

return helloService.evict(String.valueOf(name));

}

失效缓存,需要和上面的case配合起来使用

curl http://localhost:8080/evict?name=yihuihui

curl http://localhost:8080/?name=yihuihui

剩下其他的相关测试类就比较好理解了,一并贴出对应的代码

aMBmUsK

@GetMapping(path = "condition")

public String t1(int age) {

return helloService.setByCondition(age);

}

@GetMapping(path = "unless")

public String t2(int age) {

return helloService.setUnless(age);

}

@GetMapping(path = "exception")

public String exception(int age) {

try {

return String.valueOf(helloService.exception(age));

} catch (Exception e) {

return e.getMessage();

}

}

@GetMapping(path = "cachePut")

public String cachePut(int age) {

return helloService.cachePut(age);

}

7. 小结

最后管理小结一下Spring提供的几个缓存注解

@Cacheable: 缓存存在,则从缓存取;否则执行方法,并将返回结果写入缓存

@CacheEvit: 失效缓存

@CachePut: 更新缓存

@Caching: 都注解组合

上面虽说可以满足常见的缓存使用场景,但是有一个非常重要的点没有说明,缓存失效时间应该怎么设置???

III. 不能错过的源码和相关知识点

0. 项目

工程:https://github.com/liuyueyi/spring-boot-demo

源码:https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/125-cache-ano

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:app开发公司(微信app开发公司)
下一篇:自贡推进一网通办工作方案(推动一网通办)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~