java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Boot  @Cacheable、@CachePut、@CacheEvict

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

作者:一个有女朋友的程序员

本文将带你从零开始掌握 Spring Boot中常用的缓存注解,并通过多个实际案例演示其强大功能_cacheevict,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧

💡 前言

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

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

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

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

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

✅ 缓存抽象原理

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

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

📌 注意:

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

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

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

也可以使用本地缓存如 CaffeineEhcache

Step 2:启用缓存

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

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

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

场景说明:

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

示例代码:

@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);
    }
}

参数说明:

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

场景说明:

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

示例代码:

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

📌 注意:

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

场景说明:

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

示例代码:

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

清空整个缓存区:

@CacheEvict(value = "users", allEntries = true)
public void clearAllUsers() {
    // 删除所有用户逻辑
}

📌 参数说明:

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

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

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

@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();
    };
}

然后在注解中使用:

@Cacheable(value = "users", keyGenerator = "customKeyGenerator")

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

application.yml 中配置:

spring:
  redis:
    timeout: 60s
  cache:
    redis:
      time-to-live: 3600000 # 1小时

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

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

示例配置:

@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. 缓存穿透、击穿、雪崩解决方案

问题解决方案
缓存穿透缓存空值、使用布隆过滤器
缓存击穿加互斥锁、设置永不过期
缓存雪崩设置不同过期时间、集群缓存

示例:防止缓存穿透

@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;
}

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

背景:

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

代码示例:

@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 平台,都应该合理使用缓存来优化系统表现。

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

到此这篇关于Spring Boot 缓存注解详解:@Cacheable、@CachePut、@CacheEvict(超详细实战版)的文章就介绍到这了,更多相关Spring Boot @Cacheable、@CachePut、@CacheEvict内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文