Spring Boot 多缓存同时写入实现方法
本文详解如何在SpringCache中通过一次业务方法调用,将同一份结果(如客户标识对象)同时写入多个命名缓存(如按customerID和accountNumber分别缓存),避免重复远程调用,提升多维度查询场景下的缓存命中率。

本文详解如何在 Spring Cache 中通过一次业务方法调用,将同一份结果(如客户标识对象)同时写入多个命名缓存(如按 customerID 和 accountNumber 分别缓存),避免重复远程调用,提升多维度查询场景下的缓存命中率。
本文详解如何在 Spring Cache 中通过一次业务方法调用,将同一份结果(如客户标识对象)同时写入多个命名缓存(如按 customerID 和 accountNumber 分别缓存),避免重复远程调用,提升多维度查询场景下的缓存命中率。
在基于 Spring 的微服务中,常遇到「一个实体可通过多种唯一键查询」的场景:例如客户信息既可通过 customerId(Long 类型)获取,也可通过 accountNumber(String 类型)获取。理想情况下,首次任一维度查询触发远程调用后,应自动将结果同步写入两个缓存,使后续任意维度查询均可直接命中——但 Spring 原生 @Cacheable 仅支持单缓存写入,无法原生满足该需求。本文提供生产就绪的解决方案。
✅ 核心思路:混合使用 @Cacheable + 显式 CacheManager 操作
最简洁、可控且无需引入额外依赖的方式是:
- 保留 @Cacheable 处理主缓存逻辑(保障基础缓存语义与 AOP 代理能力);
- 在方法体内通过注入的 CacheManager 手动向另一个缓存写入相同结果。
? 示例实现
@Service
@RequiredArgsConstructor
public class CachedIdentifiersService {
private final LazyIdentifiersService slowService;
private final CacheManager cacheManager;
// 获取缓存实例(推荐在构造时初始化,避免每次调用 getCache())
private final Cache cacheById = cacheManager.getCache("identifiers_cache_by_customer_id");
private final Cache cacheByAccount = cacheManager.getCache("identifiers_cache_by_account_number");
@Cacheable(value = "identifiers_cache_by_customer_id", key = "#customerId")
public Identifiers getIdentifiers(Long customerId) {
Identifiers identifiers = slowService.getIdentifiers();
// ✅ 主动写入 accountNumber 缓存
if (identifiers != null && identifiers.getAccountNumber() != null) {
cacheByAccount.put(identifiers.getAccountNumber(), identifiers);
}
return identifiers;
}
@Cacheable(value = "identifiers_cache_by_account_number", key = "#accountNumber")
public Identifiers getIdentifiers(String accountNumber) {
Identifiers identifiers = slowService.getIdentifiers();
// ✅ 主动写入 customerId 缓存
if (identifiers != null && identifiers.getCustomerId() != null) {
cacheById.put(identifiers.getCustomerId(), identifiers);
}
return identifiers;
}
}? 注意:cacheManager.getCache("xxx") 返回 Cache 实例为线程安全对象,可安全复用。
⚠️ 关键注意事项
- 空值/异常处理:若 slowService.getIdentifiers() 返回 null 或抛出异常,@Cacheable 默认不缓存,此时手动 put 也应跳过(示例中已通过 if (identifiers != null) 防御)。
- 键唯一性保障:确保 Identifiers.accountNumber 和 customerId 在业务上严格唯一,否则会导致缓存覆盖或脏数据。
- 并发安全:当多个线程同时请求同一客户(如线程 A 查 customerId=100,线程 B 查 accountNumber="ACC001"),可能触发多次远程调用。Spring 的 @Cacheable(sync = true) 仅对同一 key 生效,无法跨 key 同步。如需强一致性,可结合分布式锁(如 RedisLockRegistry)或升级为「单入口缓存加载 + 多维索引维护」架构。
- 缓存失效联动:若需删除客户数据,必须同时清除两个缓存中的对应条目:
public void evictCustomer(Long customerId, String accountNumber) { cacheById.evict(customerId); cacheByAccount.evict(accountNumber); }
? 替代方案对比(不推荐用于本场景)
| 方案 | 说明 | 局限性 |
|---|---|---|
| @CachePut 组合 | 尝试用 @Cacheable 读 + @CachePut 写另一缓存 | Spring AOP 代理限制:同一 Bean 内部方法调用不触发 @CachePut,必须拆分为不同 Bean |
| 自定义 CacheResolver | 动态决定写入哪些缓存 | 无法区分「读操作」和「写操作」,易导致缓存污染 |
| AOP 切面拦截 | 在 @Cacheable 方法返回后统一写多缓存 | 侵入性强、调试复杂,且难以精准捕获 key 和 result |
✅ 总结
单次调用写入多缓存的本质,是在 Spring Cache 的声明式语义之上,补充命令式缓存操作。本文提供的 CacheManager 显式写入方案平衡了简洁性、可读性与可控性,适用于绝大多数中高并发业务场景。只要遵循「主缓存由 @Cacheable 管理,副缓存由代码显式维护」的原则,并做好键唯一性与失效一致性保障,即可高效支撑多维度快速检索需求。
WPS Office是一款面向macOS用户的综合办公套件,将文字处理、电子表格、演示文稿、PDF工具、模板与云协作整合在同一应用中。它兼容常见Microsoft Office格式,支持Intel及Apple芯片Mac,基础功能可免费使用,
Shapr3D是一款面向工业设计、机械工程、建筑概念和三维打印工作流的CAD软件。Mac版采用Parasolid建模内核,支持草图约束、实体建模、工程图、可视化渲染及常见CAD格式交换,并可通过账户在多台设备之间同步项目。
REAPER是Cockos开发的数字音频工作站,提供多轨音频与MIDI录制、剪辑、处理、混音和母带制作工具。Mac版兼容Intel与Apple芯片,支持AU、VST、VST3、CLAP等插件格式,并提供高度可定制的工作流程。
Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理工具,可在 Windows 上完成照片修饰、选区抠图、图层合成、文字排版、绘画及生成式编辑。软件采用订阅授权,由 Creative Cloud 管理安装、更新与许
Adobe InDesign 是面向印刷与数字出版的专业页面排版工具,可制作书籍、杂志、宣传册、海报、交互式 PDF 和电子书。它提供精细的文字样式、多页面管理、印前检查及多格式输出能力,并能与 Photoshop、Illustrator
Adobe Illustrator 是用于绘制矢量图形、插画、图标、徽标和版式的专业设计工具。它以路径和锚点为核心,作品放大后仍能保持清晰,并提供画板、文字、渐变、图像描摹及精确变换等功能,适合品牌视觉、印刷物料、数字界面和商业插画创作。













