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

使用默认Key时Spring Cacheable不生效问题求助

问题分析与解决方案

我来帮你梳理下这个缓存失效的问题,这其实是Spring Cache默认key生成策略结合POJO字段处理的一个常见坑。

问题根源

Spring Cache默认使用SimpleKeyGenerator生成缓存key:当方法只有一个参数时,直接把这个参数实例作为缓存key。缓存命中的核心要求是两次请求的参数实例hashCode()相等且equals()返回true。

从你的代码和请求信息来看,有两个关键疑点:

  1. equals()和hashCode()包含未在请求中传递的字段:你的DashboardRequest的这两个方法里包含了organizer字段,但请求payload里并没有这个字段。如果在请求处理过程中(比如反序列化后、进入Controller前),有其他逻辑给organizer设置了不同的值(比如每次生成新对象、随机值),那每次的DashboardRequest实例hashCode会不一样,equals()也会返回false,导致缓存key不匹配,无法命中。
  2. 请求中的部分字段未加入equals()和hashCode():你的请求payload里有state和district字段,但这两个字段并没有出现在equals()和hashCode()中。虽然这不是当前缓存失效的直接原因,但会导致即使这两个字段值不同,也会被认为是相同的请求,可能不符合业务预期。

而你用key="#dashboardRequest.level"时,只基于固定值1生成key,所以不管其他字段如何变化,key始终一致,自然能正常缓存。

解决方案

根据你的场景,推荐以下几种解决方式:

方案一:修正equals()和hashCode()方法

确保这两个方法只包含需要参与缓存key判断的字段,排除那些会被动态修改或不属于请求传递的字段:

  • 打开Eclipse,右键DashboardRequest类 → Source → Generate hashCode() and equals()
  • 在弹出的对话框中,选中所有请求payload里的字段(fromDate、toDate、theme、activity、level、levelValue、state、district),取消选中organizer(如果它不是请求传递的字段且会被动态修改)
  • 点击Finish生成新的方法代码

方案二:显式指定包含所有必要字段的SpEL key

如果不想修改POJO的方法,可以直接用SpEL指定key包含所有需要的字段,比如:

@Cacheable(value="myDash", key="new org.springframework.cache.interceptor.SimpleKey(#dashboardRequest.fromDate, #dashboardRequest.toDate, #dashboardRequest.theme, #dashboardRequest.activity, #dashboardRequest.level, #dashboardRequest.levelValue, #dashboardRequest.state, #dashboardRequest.district)")

SimpleKey会自动处理字段为null的情况,生成稳定的key。

方案三:自定义KeyGenerator

如果多个方法需要类似的key生成逻辑,可以自定义一个KeyGenerator,指定哪些字段参与key的生成:

@Component
public class DashboardKeyGenerator implements KeyGenerator {
    @Override
    public Object generate(Object target, Method method, Object... params) {
        DashboardRequest request = (DashboardRequest) params[0];
        return new SimpleKey(request.getFromDate(), request.getToDate(), request.getTheme(), 
                            request.getActivity(), request.getLevel(), request.getLevelValue(), 
                            request.getState(), request.getDistrict());
    }
}

然后在@Cacheable中指定:

@Cacheable(value="myDash", keyGenerator="dashboardKeyGenerator")

验证方法

你可以在Controller方法开头加入日志,打印dashboardRequest的hashCode()和organizer字段值:

LOGGER.info("Request hashCode: {}, organizer: {}", dashboardRequest.hashCode(), dashboardRequest.getOrganizer());

如果每次请求的hashCode不同,或者organizer字段值不一致,就验证了我们的推测。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:07:26