Spring Boot 缓存注解详解:@Cacheable、@CachePut、@CacheEvict(超详细实战版)

💡 前言

在高并发、高性能的系统开发中,缓存是提升接口响应速度和降低数据库压力的重要手段 。Spring Boot 提供了强大的缓存抽象层 ------ spring-context-support,并结合 JSR-107 标准,提供了多个缓存注解,如:

  • @Cacheable
  • @CachePut
  • @CacheEvict

这些注解可以让我们在不侵入业务逻辑的前提下,轻松实现方法级别的缓存管理。

本文将带你从零开始掌握 Spring Boot 中常用的缓存注解,并通过多个实际案例演示其强大功能,包括:

  • 查询缓存优化
  • 数据更新同步
  • 删除缓存策略
  • 多级缓存架构设计
  • Redis 实战整合
  • 缓存穿透、击穿、雪崩的解决方案

无论你是初学者,还是有一定经验的开发者,这篇文章都能让你快速上手 Spring Boot 缓存机制!


📦 一、Spring Boot 缓存核心机制概述

✅ 缓存抽象原理

Spring 的缓存机制基于 AOP 实现,本质上是在方法执行前后插入缓存逻辑:

注解 功能
@Cacheable 先查缓存,有则返回;没有则执行方法并将结果缓存
@CachePut 执行方法后更新缓存(常用于新增或更新操作)
@CacheEvict 清除缓存(常用于删除或刷新缓存)

📌 注意:

  • 这些注解只能用在 public 方法上;
  • 只有当调用方通过 Spring 代理调用该方法时才生效(即不能在同一个类中直接调用带注解的方法);
  • 需要启用缓存功能:@EnableCaching

🛠️ 二、快速入门:开启缓存支持

Step 1:添加依赖(以 Redis 为例)

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

也可以使用本地缓存如 CaffeineEhcache

Step 2:启用缓存

java 复制代码
@SpringBootApplication
@EnableCaching
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

🔁 三、三大缓存注解详解与实战

✅ 1. @Cacheable:查询缓存,避免重复计算

场景说明:

当你有一个查询接口,数据变更频率低,但查询频繁,就可以使用 @Cacheable 来缓存结果。

示例代码:
java 复制代码
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Cacheable(value = "users", key = "#userId")
    public User getUserById(Long userId) {
        System.out.println("【真实查询】用户ID:" + userId);
        return userRepository.findById(userId).orElse(null);
    }
}
参数说明:
  • value / cacheNames:指定缓存名称,可理解为缓存区域;
  • key:缓存键,默认使用参数生成;
  • unless:条件判断,例如 unless = "#result == null" 表示结果为空时不缓存;
  • condition:根据条件决定是否缓存,例如 condition = "#userId > 0"

✅ 2. @CachePut:更新缓存,保持一致性

场景说明:

当你对数据进行了更新或新增操作,需要同步更新缓存,保证下次查询拿到的是最新数据。

示例代码:
java 复制代码
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
    return userRepository.save(user);
}

📌 注意:

  • @CachePut 总是会执行方法体,并将结果放入缓存;
  • 常用于新增、修改等写操作。

✅ 3. @CacheEvict:清除缓存,强制刷新

场景说明:

当你删除某个数据或批量清空缓存时,就需要使用 @CacheEvict

示例代码:
java 复制代码
@CacheEvict(value = "users", key = "#userId")
public void deleteUser(Long userId) {
    userRepository.deleteById(userId);
}
清空整个缓存区:
java 复制代码
@CacheEvict(value = "users", allEntries = true)
public void clearAllUsers() {
    // 删除所有用户逻辑
}

📌 参数说明:

  • allEntries = true:清空该缓存区域下的所有键;
  • beforeInvocation = true:是否在方法执行前清空缓存(默认 false,在方法执行后)。

🎯 四、进阶技巧与最佳实践

✅ 1. 自定义缓存 Key 生成策略

可以通过实现 KeyGenerator 接口自定义缓存 key 的生成方式:

java 复制代码
@Bean
public KeyGenerator customKeyGenerator() {
    return (target, method, params) -> {
        StringBuilder sb = new StringBuilder();
        sb.append(target.getClass().getSimpleName());
        sb.append(method.getName());
        for (Object obj : params) {
            sb.append(obj.toString());
        }
        return sb.toString();
    };
}

然后在注解中使用:

java 复制代码
@Cacheable(value = "users", keyGenerator = "customKeyGenerator")

✅ 2. 设置缓存过期时间(以 Redis 为例)

application.yml 中配置:

java 复制代码
spring:
  redis:
    timeout: 60s
  cache:
    redis:
      time-to-live: 3600000 # 1小时

✅ 3. 多级缓存策略(Redis + Caffeine)

为了进一步提升性能,可以采用"本地缓存 + 分布式缓存"的组合方案:

  • 使用 Caffeine 作为本地缓存,减少网络开销;
  • 使用 Redis 作为分布式缓存,确保多节点间数据一致。
示例配置:
java 复制代码
@Configuration
public class CacheConfig {

    @Bean
    public CacheManager caffeineCacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager("localUsers");
        cacheManager.setCacheBuilder(Caffeine.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES));
        return cacheManager;
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }
}

✅ 4. 缓存穿透、击穿、雪崩解决方案

问题 解决方案
缓存穿透 缓存空值、使用布隆过滤器
缓存击穿 加互斥锁、设置永不过期
缓存雪崩 设置不同过期时间、集群缓存
示例:防止缓存穿透
java 复制代码
@Cacheable(value = "products", key = "#productId", unless = "#result == null")
public Product getProductById(Long productId) {
    Product product = productRepository.findById(productId).orElse(null);
    if (product == null) {
        // 缓存空值,防止缓存穿透
        redisService.setWithExpire("product:" + productId, "", 60, TimeUnit.SECONDS);
    }
    return product;
}

🧩 五、综合案例:商品信息缓存实战

背景:

我们有一个商品服务,包含如下功能:

  • 查询商品详情(缓存)
  • 更新商品信息(更新缓存)
  • 删除商品(清除缓存)

代码示例:

java 复制代码
@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;

    @Cacheable(value = "products", key = "#productId")
    public Product getProductById(Long productId) {
        return productRepository.findById(productId).orElse(null);
    }

    @CachePut(value = "products", key = "#product.id")
    public Product updateProduct(Product product) {
        return productRepository.save(product);
    }

    @CacheEvict(value = "products", key = "#productId")
    public void deleteProduct(Long productId) {
        productRepository.deleteById(productId);
    }
}

📘 六、常见问题与解决方案

问题 原因 解决办法
注解不生效 没加 @EnableCaching 添加注解
同一类内调用失效 AOP 代理失效 将方法抽离到另一个 Bean 中
缓存未更新 没使用 @CachePut@CacheEvict 加上对应注解
key 冲突 key 重复导致覆盖 使用更细粒度的 key 策略
不支持序列化 缓存对象未实现 Serializable 使用 JSON 序列化或实现接口

🧭 七、总结对比表

注解 作用 是否执行方法 适用场景
@Cacheable 查询缓存 有缓存则跳过方法 查询频繁、更新少的数据
@CachePut 更新缓存 总是执行方法 新增/修改操作
@CacheEvict 删除缓存 总是执行方法 删除或刷新缓存

🎁 八、结语

Spring Boot 的缓存注解为我们提供了一种声明式的缓存管理方式,极大地提升了开发效率和系统性能。无论是构建企业级后台系统,还是搭建高并发 API 平台,都应该合理使用缓存来优化系统表现。

通过本文的学习,你已经掌握了:

  • 如何使用 @Cacheable@CachePut@CacheEvict
  • 如何结合 Redis 或本地缓存进行实际应用;
  • 如何避免缓存穿透、雪崩、击穿等问题;
  • 如何提高系统的响应速度和稳定性。

🎯 点赞、收藏、转发本文,让更多开发者受益!

相关推荐
风象南几秒前
SpringBoot 控制器的动态注册与卸载
java·spring boot·后端
我是一只代码狗27 分钟前
springboot中使用线程池
java·spring boot·后端
hello早上好40 分钟前
JDK 代理原理
java·spring boot·spring
PanZonghui44 分钟前
Centos项目部署之运行SpringBoot打包后的jar文件
linux·spring boot
沉着的码农1 小时前
【设计模式】基于责任链模式的参数校验
java·spring boot·分布式
zyxzyx6661 小时前
Flyway 介绍以及与 Spring Boot 集成指南
spring boot·笔记
Fireworkitte2 小时前
Redis 源码 tar 包安装 Redis 哨兵模式(Sentinel)
数据库·redis·sentinel
西岭千秋雪_3 小时前
Redis性能优化
数据库·redis·笔记·学习·缓存·性能优化
一头生产的驴3 小时前
java整合itext pdf实现自定义PDF文件格式导出
java·spring boot·pdf·itextpdf
en-route3 小时前
HTTP 缓存
网络协议·http·缓存