@Cacheable、@CachePut和@CacheEvict三个注解的使用及区别
在Spring缓存体系中,@Cacheable在缓存命中时跳过方法执行,适用于读操作;@CachePut始终执行方法并强制更新缓存,适用于写操作;@CacheEvict用于删除缓存条目或清空整个缓存。三者需注意键一致性及事务与缓存顺序,避免数据不一致。
在Spring框架的缓存体系中,@Cacheable、@CachePut和@CacheEvict可以说是最常用的三个注解,它们各自负责不同的缓存生命周期管理。和Redis这类缓存中间件搭配使用时,这几个注解能帮我们省去大量手动操作缓存的重复代码。

不过,虽然它们看起来很像,但在实际业务中怎么选、怎么搭配,还是有些门道的。下面就来拆解一下各自的核心用法和适用场景。
@Cacheable
作用
方法执行前会先去缓存里查一下,如果命中,直接返回缓存的值,方法体根本不会执行——这也就是所谓的“缓存命中”。如果没查到,那就老老实实执行方法,再把结果塞进缓存。
适用场景
- 典型的读操作,比如根据用户ID获取用户信息。
- 适合数据变动频率低、结果稳定的场景。如果数据老在变,用
@Cacheable反而容易读到过时数据。
关键参数
value/cacheNames:缓存的名字,比如"users"。key:缓存的键,支持SpEL表达式,灵活度很高。condition/unless:条件控制,比如只有ID大于10时才进行缓存。
示例
@Cacheable(value = "users", key = "#id")
public User getUserById(Long id) {
// 查询数据库
return userRepository.findById(id);
}@CachePut
作用
和@Cacheable不同,@CachePut不管缓存里有没有,都会先执行方法体,然后把返回值更新到缓存中。它更像是“强制刷新缓存”的存在。
适用场景
- 典型的写操作,比如修改用户信息后同时更新缓存,确保缓存里的数据是最新的。
- 适合需要保持缓存与数据库严格一致的场景。
关键参数
参数类型和@Cacheable一致,但有一个容易被忽略的点——key的生成逻辑必须和@Cacheable保持同步,否则更新后缓存可能覆盖不到旧值,导致数据不一致。
示例
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
// 更新数据库
userRepository.update(user);
return user; // 更新后的结果存入缓存
}@CacheEvict
作用
从缓存里删数据。可以精确删除某个key对应的缓存条目,也可以一口气清空整个缓存空间。支持在方法调用前或调用后触发。
适用场景
- 删除操作,比如删掉某个用户后,一并把缓存清理掉。
- 批量更新或全量刷新场景,比如定时刷新用户列表缓存,或者清空某个业务缓存区域。
关键参数
allEntries:设为true时清空整个缓存,默认只删除指定key对应的条目。beforeInvocation:设为true时,方法执行前就会删缓存;默认是在方法执行后删除。
示例
@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生成逻辑必须一致。假如你在查询时用#id,更新时也用#user.id,看起来差不多,一旦逻辑有偏差,更新后的数据很可能不会覆盖旧的缓存。
事务与缓存的顺序
默认情况下,缓存操作是在方法执行后触发的。如果方法还加了@Transactional,需要特别留意缓存操作是否在事务提交后才执行。顺序不对,事务回滚了但缓存已经更新了,就会出现脏数据。
条件过滤
condition和unless这两个参数值得多用。比如加上unless="#result == null",可以避免把null值写进缓存,减少不必要的缓存占用和对异常情况的污染。
分布式锁
高并发场景下,单纯依赖这几个注解可能还不够。比如热点 key 穿透到数据库,引发缓存击穿或雪崩,这时候就需要结合分布式锁(比如 Redis 的 RedLock)来做兜底保护。
总结
三个注解各司其职:@Cacheable负责读且缓存,@CachePut负责强制刷新,@CacheEvict负责清理。理解它们的行为差异,再根据业务场景合理组合,就能把缓存的作用发挥出来。
Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。
极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。
















