@Cacheable、@CachePut和@CacheEvict三个注解的使用及区别

 更新时间:2026年05月21日 10:07:07   作者:dushky  
@Cacheable、@CachePut和@CacheEvict是Spring框架中的核心缓存注解,分别用于查询、更新和删除缓存操作,@Cacheable在缓存命中时跳过方法执行;@CachePut强制执行并更新缓存;@CacheEvict删除或清空缓存,注意事项包括键的一致性、事务处理和条件过滤等

在 Spring 框架中,@Cacheable@CachePut 和 @CacheEvict 是三个与缓存管理相关的核心注解,它们与 Redis 等缓存中间件结合使用时,可以显著提升应用性能。

以下是它们的核心区别和适用场景:

@Cacheable

作用

在方法执行前检查缓存,如果缓存中存在对应结果,直接返回缓存值,跳过方法执行;若不存在,则执行方法并将返回值存入缓存。

适用场景

  • 查询操作(例如根据 ID 查询用户信息)。
  • 适用于结果稳定、不频繁变更的数据。

关键参数

  • value/cacheNames:缓存名称(如 "users")。
  • key:缓存的键(支持 SpEL 表达式)。
  • condition/unless:缓存条件(如 condition="#id > 10")。

示例

@Cacheable(value = "users", key = "#id")
public User getUserById(Long id) {
    // 查询数据库
    return userRepository.findById(id);
}

@CachePut

作用

无论缓存是否存在,始终执行方法,并将返回值更新到缓存中。适用于需要强制刷新缓存的场景。

适用场景

  • 更新操作(例如修改用户信息后同步更新缓存)。
  • 需要确保缓存与数据库数据一致。

关键参数

与 @Cacheable 相同,但需确保 key 的生成逻辑与 @Cacheable 一致,否则可能导致缓存不一致。

示例

@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
    // 更新数据库
    userRepository.update(user);
    return user; // 更新后的结果存入缓存
}

@CacheEvict

作用

删除指定缓存条目或清空整个缓存。支持在方法调用触发。

适用场景

  • 删除操作(例如删除用户后清除缓存)。
  • 数据变更后需要清理旧缓存(如批量更新后清空列表缓存)。

关键参数

  • allEntries:是否清空整个缓存(默认为 false,仅删除 key 对应的条目)。
  • beforeInvocation:是否在方法执行前删除缓存(默认为 false,方法执行后删除)。

示例

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

// 清空整个缓存
@CacheEvict(value = "users", allEntries = true)
public void refreshAllUsers() {
    // 无需实际逻辑,仅触发缓存清理
}

三者的核心区别

注解是否执行方法体缓存行为典型场景
@Cacheable缓存命中时跳过读取缓存或写入新结果查询(幂等操作)
@CachePut始终执行强制更新缓存更新(非幂等)
@CacheEvict通常执行删除缓存条目或清空整个缓存删除或清理缓存

注意事项

键的一致性

@Cacheable 和 @CachePut 的 key 生成逻辑必须一致,否则更新后可能无法覆盖旧缓存。

事务与缓存的顺序

默认情况下,缓存操作在方法执行后触发。若方法有事务,需确保缓存操作在事务提交后执行(可通过 @Transactional 配置)。

条件过滤

使用 condition 和 unless 避免缓存无效数据(如 unless="#result == null")。

分布式锁

在高并发场景下,结合分布式锁(如 Redis 的 RedLock)避免缓存击穿或雪崩。

总结

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

相关文章

  • mybatis update set 多个字段实例

    mybatis update set 多个字段实例

    这篇文章主要介绍了mybatis update set 多个字段实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • 浅谈Java平台无关性

    浅谈Java平台无关性

    这篇文章主要介绍了浅谈Java平台无关性,对此感兴趣的同学,可以多了解一下
    2021-04-04
  • SpringCloud组件性能优化的技巧

    SpringCloud组件性能优化的技巧

    这篇文章主要介绍了SpringCloud组件性能优化的技巧,Springcloud 原始的配置,性能是很低的,大家可以使用 Jmeter 测试一下,QPS 不会到 50,要做到高并发,需要做不少的配置优化,需要的朋友可以参考下
    2023-09-09
  • Java中的synchronized重量级锁解析

    Java中的synchronized重量级锁解析

    这篇文章主要介绍了Java中的synchronized重量级锁解析,内核需要去申请这个互斥量,必须要进入内核态,也就是这里需要用户态,内核态的切换,状态的切换,开销是比较大的,这就是重型锁的一个弊端,需要的朋友可以参考下
    2024-01-01
  • 从java8升级java17的一些调整总结

    从java8升级java17的一些调整总结

    在过去的几年里,Java经历了多次版本升级,从JDK8到JDK17,每一次升级都带来了许多新的特性和改进,这篇文章主要介绍了从java8升级java17的一些调整,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2026-03-03
  • 使用Java 8中的Lambda表达式实现工厂模式

    使用Java 8中的Lambda表达式实现工厂模式

    这篇文章主要给大家介绍了使用Java 8中的Lambda表达式实现工厂模式的相关资料,文中介绍的非常详细,对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。
    2017-04-04
  • Java设计模式之单例模式示例详解

    Java设计模式之单例模式示例详解

    单例模式是最简单也是最基础的设计模式之一,单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。本文将通过一些示例代码为大家详细介绍一下单例模式,感兴趣的可以了解一下
    2021-12-12
  • 基于java语言实现快递系统

    基于java语言实现快递系统

    这篇文章主要为大家详细介绍了基于java语言实现快递系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • springcloud feign调其他微服务时参数是对象的问题

    springcloud feign调其他微服务时参数是对象的问题

    这篇文章主要介绍了springcloud feign调其他微服务时参数是对象的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • 分布式系统中的降级熔断设计问题面试

    分布式系统中的降级熔断设计问题面试

    这篇文章主要为大家介绍了分布式系统中的降级熔断设计问题面试解答,有需要的朋友可以借鉴参考下,希望能有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03

最新评论