SpringBoot缓存注解@Cacheable使用姿势介绍

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

本文主要知识点:

  • @Cacheable: 缓存存在,则使用缓存;不存在,则执行方法,并将结果塞入缓存
  • @CacheEvit: 失效缓存
  • @CachePut: 更新缓存

I. 项目环境

1. 项目依赖

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

开一个web服务用于测试

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
</dependencies>

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

II. 缓存注解介绍

1. @Cacheable

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

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

	/**
	 * 与 cacheNames 效果等价
	 */
	@AliasFor("cacheNames")
	String[] value() default {};

	
	@AliasFor("value")
	String[] cacheNames() default {};

	/**
	 * 缓存key
	 */
	String key() default "";

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

一个简单的使用姿势

/**
 * 首先从缓存中查,查到之后,直接返回缓存数据;否则执行方法,并将结果缓存
 * <p>
 * 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);
    }
}

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

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

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

@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: 都注解组合
  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: @CacheableSpring框架提供的一个注解,用于将对应的方法的返回结果存储在缓存中,以便下次请求时直接从缓存中获取结果,提高系统性能。 使用Redis作为缓存提供商,可以通过配置Redis作为Cache Manager来实现@Cacheable使用Redis。下面是具体的步骤: 1. 引入依赖:在项目的pom.xml文件中添加Spring框架的相关依赖和Redis的客户端依赖,如spring-boot-starter-data-redis等。 2. 配置Redis:在项目的配置文件中设置Redis的连接信息,包括host、port、password等。可以通过application.properties或application.yml文件进行配置。 3. 创建Redis连接工厂:使用Redis连接信息创建一个Redis连接工厂Bean,用于创建Redis连接。 4. 创建Cache Manager:使用Redis连接工厂创建一个Cache Manager Bean,该Cache Manager将使用Redis作为缓存提供商。 5. 配置@Cacheable注解:在需要使用缓存的方法上添加@Cacheable注解,并指定缓存的名称,如@Cacheable(value = "userCache")。该注解还可以指定缓存的key,以便根据不同的参数生成不同的缓存key。 6. 运行项目:启动项目后,当使用@Cacheable注解修饰的方法被调用时,系统会先检查缓存中是否存在对应的结果。如果存在,则从缓存中获取结果并返回;如果不存在,则调用方法,然后将方法的返回结果存储在缓存中,以供后续使用。 通过以上步骤,可以让@Cacheable注解使用Redis作为缓存提供商,提高系统的性能和响应速度。同时,使用Redis作为缓存存储,还可以实现分布式缓存,增加系统的可扩展性和稳定性。 ### 回答2: @CacheableSpring框架提供的一个注解,用于为方法添加缓存功能。当方法被调用时,如果缓存中存在相应的缓存结果,则直接从缓存中获取,而不会执行方法。如果缓存中不存在相应的缓存结果,则执行方法,并将方法的返回结果存入缓存中,以备后续使用。 当@Cacheable和Redis结合使用时,可以将返回结果以键值对的形式存储在Redis缓存服务器中。Redis是一种内存数据库,具有快速读写的特点。通过使用Redis作为缓存服务器,可以提高缓存的读写性能。 使用@Cacheable注解时,需配置Redis作为缓存存储的方式。可以通过在Spring的配置文件中指定Redis相关的属性,比如Redis的连接信息、缓存的过期时间等。 在方法被调用时,@Cacheable会先检查Redis中是否存在相应的缓存结果。如果存在,则直接从Redis中读取缓存结果并返回。如果不存在,则执行方法,并将方法的返回结果存储在Redis中,以备后续使用使用Redis作为缓存服务器,可以解决传统基于内存的缓存机制的性能瓶颈问题。由于Redis将缓存数据存储在内存中,读写速度快,能够极大地提高应用程序的性能。 综上所述,通过将@Cacheable与Redis结合使用,可以实现高效的缓存机制,提高系统的响应速度和性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1b( ̄▽ ̄)d 

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值