商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Spring Boot 多缓存同时写入实现方法

Spring Boot 多缓存同时写入实现方法

  发布于2026-04-20 阅读(0)

扫一扫,手机访问

Spring Boot 中实现单次调用写入多个缓存的完整方案

本文详解如何在 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 管理,副缓存由代码显式维护」的原则,并做好键唯一性与失效一致性保障,即可高效支撑多维度快速检索需求。

本文转载于:互联网 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注