当前位置: 首页 > news >正文

@Cacheable 和 @CacheEvict 注解的详细使用说明及参数解析,结合 Spring Cache 的核心功能和实际开发场景

一、@Cacheable 注解详解

1. 核心作用

@Cacheable 用于标记方法的返回值需要被缓存。
执行逻辑

  • 方法调用前检查缓存:若缓存存在且有效,直接返回缓存值;否则执行方法并将结果存入缓存。

2. 关键参数

参数名作用示例
value/cacheNames必填,指定缓存名称(命名空间),可配置多个缓存。@Cacheable(value = "users", key = "#id")
key指定缓存键(支持 SpEL 表达式),默认使用方法参数生成键。key = "#id" 或 key = "#user.name"
condition方法执行前判断条件,满足时才缓存结果(SpEL 表达式)。condition = "#id > 0"
unless方法执行后判断条件,满足时  缓存结果(SpEL 表达式)。unless = "#result == null"
sync是否同步执行缓存(防止并发重复计算),默认 falsesync = true
cacheManager指定使用的 CacheManager 实现(如 Redis、Caffeine)。cacheManager = "redisCacheManager"
cacheResolver自定义缓存解析器(高级用法,用于动态选择缓存)。cacheResolver = "customCacheResolver"

3. 使用场景

  • 查询操作:如根据 ID 查询用户、商品信息。
  • 静态数据:如配置项、字典表数据,更新频率低。
  • 高频读取:减少数据库或远程调用压力。

4. 示例代码

@Cacheable(value = "users", key = "#id", condition = "#id > 0", unless = "#result == null"
)
public User getUserById(Long id) {// 查询数据库逻辑return userRepository.findById(id);
}

解释

  • value = "users":缓存名称为 users
  • key = "#id":缓存键为参数 id
  • condition = "#id > 0":仅当 id > 0 时才缓存结果。
  • unless = "#result == null":若查询结果为 null,不缓存(防止空值占用缓存空间)。

二、@CacheEvict 注解详解

1. 核心作用

@CacheEvict 用于清除缓存条目。
执行逻辑

  • 方法执行后(或前)删除指定缓存条目或清空整个缓存区域。

2. 关键参数

参数名作用示例
value/cacheNames必填,指定要清除的缓存名称(命名空间)。@CacheEvict(value = "users", key = "#id")
key指定要清除的缓存键(支持 SpEL 表达式)。key = "#id" 或 key = "#user.name"
allEntries是否清空整个缓存区域(默认 false,仅清除单个键)。allEntries = true
beforeInvocation是否在方法执行前清除缓存(默认 false,方法执行后清除)。beforeInvocation = true
condition方法执行前判断条件,满足时才清除缓存(SpEL 表达式)。condition = "#id > 0"

3. 使用场景

  • 删除操作:如删除用户后清除对应缓存。
  • 更新操作:如修改用户信息后清除旧缓存。
  • 批量操作:清空整个缓存区域(如更新配置后刷新所有缓存)。

4. 示例代码

4.1 清除单个缓存条目
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {// 删除数据库逻辑userRepository.deleteById(id);
}

解释

  • value = "users":清除 users 缓存区域。
  • key = "#id":清除键为 id 的缓存条目。
4.2 清空整个缓存区域
@CacheEvict(value = "users", allEntries = true)
public void refreshAllUsersCache() {// 刷新所有用户缓存逻辑userRepository.refresh();
}

解释

  • allEntries = true:清空 users 缓存区域的所有条目。
4.3 在方法执行前清除缓存
@CacheEvict(value = "users", key = "#id", beforeInvocation = true
)
public User updateUser(User user) {// 更新数据库逻辑return userRepository.save(user);
}

解释

  • beforeInvocation = true:方法执行前清除缓存(适用于需先清除旧数据再更新的场景)。

三、@Cacheable 与 @CacheEvict 的对比

特性@Cacheable@CacheEvict
作用缓存方法返回值清除缓存条目或区域
执行时机方法执行前(命中缓存则跳过方法)方法执行后(或前,通过 beforeInvocation
是否影响方法执行可能跳过方法执行始终执行方法,仅影响缓存状态
关键参数valuekeyconditionunlessvaluekeyallEntriesbeforeInvocation
适用场景查询操作、静态数据删除/更新操作、缓存刷新

四、高级用法与注意事项

1. 条件控制:condition vs unless

  • condition方法执行前判断是否触发缓存逻辑。
    @Cacheable(value = "users", key = "#id", condition = "#id > 0")
    public User getUserById(Long id) {return userRepository.findById(id);
    }
  • unless方法执行后判断是否缓存结果。
    @Cacheable(value = "users", key = "#id", unless = "#result == null")
    public User getUserById(Long id) {return userRepository.findById(id);
    }

2. 缓存键生成策略

  • 默认键生成:使用方法参数生成键(如 SimpleKey)。
  • 自定义键:通过 SpEL 表达式指定键(如 #id#user.name)。
  • 复杂对象:使用 #root.methodName 或 #root.method 动态生成键。

3. 缓存一致性保障

  • 删除操作后清除缓存:确保数据库与缓存数据一致。
  • 更新操作后更新缓存:使用 @CachePut 强制刷新缓存(见下文)。

4. 异常处理

  • @CacheEvict 的 beforeInvocation
    • 若 beforeInvocation = true,方法抛出异常时仍会清除缓存(需谨慎)。
  • @Cacheable 的 unless
    • 若方法抛出异常,不会缓存结果。

五、组合使用示例

1. 同时使用 @Cacheable 和 @CacheEvict

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

2. 使用 @Caching 组合多个操作

@Caching(cacheable = @Cacheable(value = "users", key = "#id"),evict = @CacheEvict(value = "userRoles", key = "#id")
)
public User getUserWithRoles(Long id) {return userRepository.findUserWithRoles(id);
}

六、常见问题与解决方案

1. 缓存穿透(Cache Penetration)

  • 问题:查询不存在的数据(如 id=invalid),导致频繁访问数据库。
  • 解决方案
    • 缓存空值:允许缓存 null 结果(unless = "#result == null" 改为 true)。
    • 布隆过滤器:前置过滤非法请求。

2. 缓存雪崩(Cache Avalanche)

  • 问题:大量缓存同时失效,导致数据库压力骤增。
  • 解决方案
    • 随机过期时间:为缓存设置不同 TTL。
    • 热点数据永不过期:对高频数据不设置过期时间。

3. 缓存击穿(Cache Breakdown)

  • 问题:热点数据过期后,大量请求直接访问数据库。
  • 解决方案
    • 互斥锁:在缓存失效时加锁,仅允许一个线程重建缓存。
    • 永不过期 + 定期刷新:对热点数据设置永不过期,后台定期刷新。

七、总结

注解核心用途典型场景
@Cacheable缓存查询结果查询接口、静态数据
@CacheEvict清除缓存删除/更新接口、缓存刷新
@CachePut强制更新缓存修改数据后同步缓存

        通过合理使用这些注解,开发者可以高效管理缓存,显著提升系统性能,同时避免缓存一致性问题。

相关文章:

  • 采样与混淆
  • 【Linux指南】文件系统基础操作与路径管理
  • 微软AD域替换,解析宁盾信创身份域管在Windows计算机加域管理上为何采用客户端方案
  • 不同网络I/O模型的原理
  • 2506C++,C++时间库与C时间
  • C++/Qt 联合编程中的定时器使用陷阱:QObject::startTimer 报错详解
  • 华为云Flexus+DeepSeek征文 | 基于华为云ModelArts Studio打造AingDesk AI聊天助手
  • iosAppStore上架流程,保姆级记录(3)
  • 基于 SpaCy 框架的依存句法分析实战指南
  • dpdk-testpmd 测试常用功能记录
  • 5. 相机拍摄简单构图
  • 音频导入规范
  • linux回收站
  • 安卓15开机启动Fallbackhome去除--成果展示
  • uniapp 页面栈一定深度后,回首页导航到新页面的解决方案
  • 【深度学习:进阶篇】--2.4.BN与神经网络调优
  • 基于RocketMQ源码理解顺序写、刷盘机制与零拷贝
  • 零基础实战:云开发家政维修小程序搭建指南
  • Cesium圆锥渐变色实现:融合顶点着色器、Canvas动态贴图与静态纹理的多方案整合
  • UE5 学习系列(五)导入贴图资产
  • 电子商务网站建设资讯/上海app开发公司
  • 如何做淘宝客个人网站/百度搜索引擎广告
  • 网站建站基础/免费网站推广软件
  • 郑州哪家做网站好/seo服务是什么
  • 网站安全建设的重要性/seo专员工资待遇
  • 上海高端网站建设定制/超级搜索引擎