SpringBoot缓存注解之@Cacheable/@CacheEvict使用方式

 更新时间:2026年05月21日 10:00:41   作者:希望永不加班  
本文介绍了SpringBoot缓存注解的使用,包括Cacheable、CacheEvict、CachePut和Cache组合等,主要解释了使用缓存注解的优势和使用方式,提供了实际使用场景,并给出了使用缓存时的一些注意事项,最后总结了Cacheable、CacheEvict和CachePut三种注解的使用场景

在 SpringBoot 里做缓存,除了手动操作 RedisTem)plate,更优雅、更常用的方式就是Spring 自带的缓存注解

不用写重复的缓存逻辑,只需要在方法上加个注解,就能自动实现缓存读写,代码干净又好维护。

本篇文章就来讲讲最核心的两个注解:

  •  @Cacheable:查询时自动缓存
  •  @CacheEvict:更新/删除时自动清理缓存

一、为什么要用缓存注解?

  • 无侵入:业务代码和缓存代码分离,不污染逻辑
  • 极简开发:一行注解替代一堆 get/set 缓存代码
  • 统一管理:过期时间、缓存名称、key 规则集中配置
  • 适配多种缓存:Redis、Caffeine、内存缓存都支持

适合:

  • 查询多、修改少的接口
  • 商品详情、用户信息、字典数据、配置列表
  • 不想写重复缓存模板代码的场景

二、基础环境准备

1. 引入依赖

<!-- Redis + 缓存 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2. 启动类开启缓存

@SpringBootApplication
@EnableCaching // 必须加
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

3. application.yml 缓存配置

spring:
  cache:
    type: redis
    redis:
      time-to-live: 3600000  # 默认1小时过期
      cache-null-values: false  # 不缓存null

三、核心注解 1:@Cacheable(查询 + 缓存)

作用:

第一次执行方法 → 查库 → 结果存入缓存

后续请求 → 直接走缓存,不执行方法体

1. 基础用法

@Cacheable(value = "userCache", key = "#userId")
public User getUserById(Long userId) {
    return userMapper.selectById(userId);
}
  •  value / cacheNames:缓存名(区分不同业务)
  •  key:缓存 key,支持 SpEL 表达式

最终 Redis key:

userCache::1001

2. 常用 key 写法

// 单个参数
@Cacheable(value = "user", key = "#id")
// 对象参数取id
@Cacheable(value = "user", key = "#user.id")
// 方法名当key
@Cacheable(value = "dict", key = "#root.methodName")
// 组合key
@Cacheable(value = "order", key = "'uid:'+#userId+':type:'+#type")

3. 条件缓存(满足才缓存)

// 只缓存成年用户
@Cacheable(value = "user", key = "#userId", condition = "#result.age >= 18")
// 结果不为null才缓存
@Cacheable(value = "user", key = "#userId", unless = "#result == null")

四、核心注解 2:@CacheEvict(删除缓存)

作用: 数据更新/删除后,清理旧缓存,保证数据一致。

1. 根据 key 删除

@CacheEvict(value = "userCache", key = "#user.id")
public void updateUser(User user) {
    userMapper.updateById(user);
}

2. 删除整个缓存名下所有 key

@CacheEvict(value = "userCache", allEntries = true)
public void refreshAllUser() {
}

3. 方法执行前删除

@CacheEvict(value = "user", key = "#userId", beforeInvocation = true)

五、另外两个常用注解

1. @CachePut

强制更新缓存,每次都会执行方法体,适合实时更新缓存。

@CachePut(value = "user", key = "#user.id")
public User updateUser(User user) {
    userMapper.updateById(user);
    return user;
}

2. @Caching

组合多个缓存操作:

@Caching(
    evict = {
        @CacheEvict(value = "user", key = "#userId"),
        @CacheEvict(value = "userOrder", key = "#userId")
    }
)
public void deleteUser(Long userId) {
}

六、模拟场景

场景 1:用户详情(典型查询缓存)

@Cacheable(value = "userInfo", key = "#userId", unless = "#result == null")
public User getUser(Long userId) {
    return userMapper.selectById(userId);
}

场景 2:修改用户 → 清理缓存

@CacheEvict(value = "userInfo", key = "#user.id")
public void updateUser(User user) {
    userMapper.updateById(user);
}

场景 3:删除用户 → 清理缓存

@CacheEvict(value = "userInfo", key = "#userId")
public void deleteUser(Long userId) {
    userMapper.deleteById(userId);
}

场景 4:商品列表缓存

@Cacheable(value = "productList", key = "#categoryId")
public List<Product> getProductList(Integer categoryId) {
    return productMapper.selectByCategory(categoryId);
}

场景 5:批量刷新商品缓存

@CacheEvict(value = "productList", allEntries = true)
public void refreshProduct() {
}

场景 6:字典/配置(几乎不变,长期缓存)

@Cacheable(value = "dictCache", key = "#dictType")
public List<Dict> getDict(String dictType) {
    return dictMapper.selectByType(dictType);
}

七、注意事项

1. 同类方法内调用,注解失效

因为走了代理,同类内部方法调用不经过 AOP。

解决:抽取到独立 Service 或自己注入自己。

2. 缓存 key 冲突

不同业务一定要用不同 value/cacheNames

3. 缓存与数据库不一致

增删改必须配合 @CacheEvict 或 @CachePut

4. 大数据量列表缓存

列表缓存容易占内存,建议设置更短过期时间 + 分页缓存。

5. null 值被缓存

用 unless = "#result == null" 避免。

6. 事务与缓存顺序问题

建议事务提交后再清缓存,否则会出现“脏缓存”。

八、@Cacheable vs @CachePut vs @CacheEvict 总结

注解

作用

执行方法体

典型场景

@Cacheable

查 + 缓存

缓存不存在才执行

查询接口

@CachePut

强制更新缓存

每次都执行

实时同步

@CacheEvict

删除缓存

每次都执行

增删改

九、总结

SpringBoot 缓存注解是后端最实用的简化技巧之一

  • 查询用 @Cacheable
  • 更新删除用 @CacheEvict
  • 实时同步用 @CachePut

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java数组中的元素删除并实现向前移的代码

    Java数组中的元素删除并实现向前移的代码

    这篇文章主要介绍了Java数组中的元素删除并实现向前移的代码的相关资料,需要的朋友可以参考下
    2016-05-05
  • Java由浅入深通关抽象类与接口上

    Java由浅入深通关抽象类与接口上

    在类中没有包含足够的信息来描绘一个具体的对象,这样的类称为抽象类,接口是Java中最重要的概念之一,它可以被理解为一种特殊的类,不同的是接口的成员没有执行体,是由全局常量和公共的抽象方法所组成,本文给大家介绍Java抽象类和接口,感兴趣的朋友一起看看吧
    2022-04-04
  • Java中有界队列的饱和策略(reject policy)原理解析

    Java中有界队列的饱和策略(reject policy)原理解析

    这篇文章主要介绍了Java中有界队列的饱和策略(reject policy)原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • MyBatis resultMap id标签的错误使用方式

    MyBatis resultMap id标签的错误使用方式

    这篇文章主要介绍了MyBatis resultMap id标签的错误使用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • 一文带你深入认识JAVA中的异常

    一文带你深入认识JAVA中的异常

    Java异常处理成为社区中讨论最多的话题之一,下面这篇文章主要给大家介绍了关于JAVA中异常的相关资料,文中通过代码介绍的非常详细,对大家学习或者使用java具有一定的参考借鉴价值,需要的朋友可以参考下
    2024-06-06
  • Java Hibernate中的持久化类和实体类关系

    Java Hibernate中的持久化类和实体类关系

    Hibernate是一种Java对象关系映射框架,通过持久化类将Java对象映射到数据库表中。持久化类需要实现无参构造器、具有标识属性和使用注解或XML进行映射。Hibernate通过Session来管理对象的状态,包括临时状态、持久化状态和游离状态
    2023-04-04
  • idea中springboot项目连接数据库报错的原因解析

    idea中springboot项目连接数据库报错的原因解析

    这篇文章主要介绍了idea中springboot项目连接数据库报错的原因解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • Spring中@Configuration注解和@Component注解的区别详解

    Spring中@Configuration注解和@Component注解的区别详解

    这篇文章主要介绍了Spring中@Configuration注解和@Component注解的区别详解,@Configuration 和 @Component 到底有何区别呢?我先通过如下一个案例,在不分析源码的情况下,小伙伴们先来直观感受一下这两个之间的区别,需要的朋友可以参考下
    2023-09-09
  • JDK1.6集合框架bug 6260652解析

    JDK1.6集合框架bug 6260652解析

    这篇文章主要为大家解析了JDK1.6集合框架bug:c.toArray might (incorrectly) not return Object[] (see 6260652),具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • springcloud使用Hystrix进行微服务降级管理

    springcloud使用Hystrix进行微服务降级管理

    这篇文章主要介绍了springcloud使用Hystrix进行微服务降级管理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04

最新评论