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代理生效:
- 开启代理暴露:在缓存配置类中添加
exposeProxy = true
@Configuration @EnableCaching(proxyTargetClass = true, exposeProxy = true) public class CacheConfig { // Redis缓存配置... }
- 通过代理对象调用
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
相关产品推荐
相关产品推荐

