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

Spring Boot中使用@CachePut更新Redis缓存列表失败求助

解决Spring Boot中@CachePut更新Redis缓存列表的问题

问题根源

你遇到的ClassCastException核心原因是同一个缓存key下存储了不同类型的数据:

  • @Cacheable注解的fetchByDate方法向custDetails:<日期>缓存key中存入了List<CustomerDetail>类型数据
  • @CachePut注解的updateCustomer方法却向同一个key中存入了单个CustomerDetail对象

当后续调用fetchByDate时,Spring尝试把缓存中的单个对象强转为列表,直接抛出类型转换异常。

另外你尝试的内部调用refreshCache方法无效,是因为Spring缓存注解基于动态代理实现,同一个类内部调用带注解的方法时,代理不会生效,@CachePut逻辑根本没执行。

解决方案

方案一:让@CachePut返回与@Cacheable相同类型的列表

修改updateCustomer方法,更新数据库后重新查询对应日期的完整列表,用@CachePut将列表存入缓存,确保类型一致:

@CachePut(value = "custDetails", key="#strDate")    
@Override
public List<CustomerDetail> updateCustomer(CustomerDetail customerDetail,String strDate) {
    // 1. 更新数据库
    custRepository.saveAndFlush(customerDetail);
    // 2. 查询该日期下的最新全量数据
    return custRepository.findByCreateDatess(strDate);
}

这样缓存中始终存储List<CustomerDetail>,和@Cacheable的类型匹配,不会再出现转换异常。

方案二:手动操作缓存(保留原方法返回值)

如果updateCustomer必须返回单个CustomerDetail,可以通过CacheManager直接操作缓存,要么删除旧缓存触发重新查询,要么主动存入新列表:

@Autowired
private CacheManager cacheManager;

@Override
public CustomerDetail updateCustomer(CustomerDetail customerDetail,String strDate) {
    CustomerDetail customerDetail2 = custRepository.saveAndFlush(customerDetail);
    
    Cache cache = cacheManager.getCache("custDetails");
    if (cache != null) {
        // 方式1:删除旧缓存,下次调用fetchByDate时自动重新查询并缓存
        cache.evict(strDate);
        
        // 方式2:主动查询最新列表并放入缓存(可选,提前预热缓存)
        // List<CustomerDetail> newList = custRepository.findByCreateDatess(strDate);
        // cache.put(strDate, newList);
    }
    
    return customerDetail2;
}

方案三:修复内部调用缓存注解的问题(不推荐)

如果坚持用内部调用refreshCache的方式,需要让Spring代理生效:

  1. 开启代理暴露:在缓存配置类中添加exposeProxy = true
@Configuration
@EnableCaching(proxyTargetClass = true, exposeProxy = true)
public class CacheConfig {
    // Redis缓存配置...
}
  1. 通过代理对象调用refreshCache:
@Override
public CustomerDetail updateCustomer(CustomerDetail customerDetail,String strDate) {
    CustomerDetail customerDetail2 = custRepository.saveAndFlush(customerDetail);
    if(customerDetail2!=null) {
        // 获取当前类的代理对象,触发@CachePut逻辑
        ((YourServiceInterface) AopContext.currentProxy()).refreshCache(strDate);
    }
    return customerDetail2;
}

@CachePut(cacheNames = "custDetails", key="#strDate")   
public List<CustomerDetail> refreshCache(String strDate){
    return custRepository.findByCreateDatess(strDate);
}

内容的提问来源于stack exchange,提问作者J. Doe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 05:33:15