You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot @Cacheable与@CachePut缓存始终为空问题求助

Spring Boot缓存始终为空的问题排查与修复

问题概述

构建Spring Boot应用处理文本文件中的加载数据,调用标注@Cacheable/@CachePut的UpdateCacheService方法后缓存始终为空,即使存在大量重复customer_id的数据也无法命中缓存,通过CacheManager直接访问缓存返回null。

核心问题分析

1. @Cacheable方法返回null导致缓存不存储

Spring Cache默认不会将null值存入缓存。loadCachedCustomerDailyData方法返回null,首次调用缓存未命中后,不会在缓存中创建任何条目,后续调用依然会执行方法返回null,导致缓存永远无数据。

2. @CachePut的key表达式错误

  • insertRecordIntoCache方法参数是DailyLoadInfo,但key使用#load.customerId,方法内不存在load参数,SpEL解析失败,无法将值存入缓存。
  • updateWeeklyCache方法参数只有BigDecimal total,key使用#load.customerId,同样无load参数,无法关联到具体客户的缓存条目。

3. @Cacheable的key字段不一致

loadCachedCustomerWeeklyTotal的key使用#load.customer_id(下划线),而其他方法使用#load.customerId(驼峰),如果Load类的字段是驼峰命名customerId,该key无法匹配到正确的缓存条目,导致缓存不命中。

4. @CacheEvict动态缓存名称的潜在问题

clearCache方法的value = "#cacheName",Spring Cache默认不支持这种动态指定缓存名称的方式(ConcurrentMapCacheManager不支持),会导致清除缓存操作失效。

修复步骤

1. 修正@Cacheable方法的返回值

缓存未命中时返回默认初始化对象,而非null,确保缓存能存储条目:

@Cacheable(value = DAILY_LOADS_CACHE, key = "#load.customerId")
public DailyLoadInfo loadCachedCustomerDailyData(Load load) {
    // 返回初始化的DailyLoadInfo,而非null
    DailyLoadInfo defaultInfo = new DailyLoadInfo();
    defaultInfo.setCustomerId(load.getCustomerId());
    defaultInfo.setTransactionDate(load.getTransactionDate());
    defaultInfo.setLoadCount(0);
    defaultInfo.setTotalAmount(BigDecimal.ZERO);
    return defaultInfo;
}

@Cacheable(value = WEEKLY_LOADS_CACHE, key = "#load.customerId")
public BigDecimal loadCachedCustomerWeeklyTotal(Load load) {
    return BigDecimal.ZERO; // 返回0会正常存入缓存
}

2. 修正@CachePut的key表达式和方法参数

确保key能正确关联到目标缓存条目,传递必要的关联参数:

@CachePut(value = DAILY_LOADS_CACHE, key = "#dailyCustomerLoadInfo.customerId")
public DailyLoadInfo insertRecordIntoCache(DailyLoadInfo dailyCustomerLoadInfo) {
    return dailyCustomerLoadInfo;
}

// 修改方法签名,传入customerId用于定位缓存key
@CachePut(value = WEEKLY_LOADS_CACHE, key = "#customerId")
public BigDecimal updateWeeklyCache(String customerId, BigDecimal total) {
    return total;
}

3. 统一@Cacheable的key字段

保持所有缓存key的字段命名一致:

@Cacheable(value = WEEKLY_LOADS_CACHE, key = "#load.customerId") // 改为驼峰的customerId
public BigDecimal loadCachedCustomerWeeklyTotal(Load load) {
    return BigDecimal.ZERO;
}

4. 修正CacheManagementService中的调用逻辑

对应修改updateWeeklyCache的调用,传入customerId:

if (isDatabaseSuccess) {
    this.lastSeenDate = this.updateCacheService.insertRecordIntoCache(dailyCustomerLoadInfo).getTransactionDate();
    // 传入load的customerId作为缓存key的参数
    this.updateCacheService.updateWeeklyCache(load.getCustomerId(), load.getLoadAmount().add(weeklyLoadAmount));
}

5. 修复@CacheEvict的动态缓存名称问题

改用CacheManager直接操作缓存,替代动态@CacheEvict:

// 移除@CacheEvict注解
public void clearCache(String cacheName) {
    Cache cache = cacheManager.getCache(cacheName);
    if (cache != null) {
        cache.clear();
    }
}

额外验证建议

  • 在缓存方法中添加日志,打印缓存命中/未命中状态,确认缓存逻辑执行情况。
  • 使用cacheManager.getCache(DAILY_LOADS_CACHE).get("528")(替换为实际customerId)在代码中打印缓存内容,验证是否成功存入。
  • 移除重复的@EnableCaching注解(主类或配置类保留一个即可),避免冗余配置。

内容的提问来源于stack exchange,提问作者Brandon Yip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 09:15:16