springcache condition #result条件不生效问题排查

本文主要是日常开发过程当中遇到的一个实际问题,以及问题排查的过程,通过本文你将了解:

  • springcache 注解中 condition 的作用原理

  • condition 以及 unless 条件判断的区别

背景

有一个用户权限查询接口,查询用户在某个应用的权限,关键的两个入参信息为

  • appCode(应用编码)
  • account(用户账号)

其中在代码逻辑里面需要将用户账号 account 转为用户统一身份id 即 uid 进行内部逻辑处理,由于 account 与 uid 得关系在外部系统存储,因此这里需要缓存 account 与 uid 得关系。缓存时长为2天,如下代码所示:

以上的逻辑预期是缓存 account 与 uid 得关系,无论 uid 是否存在, 不存在的话缓存 null 值(可通过 CacheManager 统一配置)。

但是后续有这样的需求,如果 uid 为 null 得时候不缓存,因此按照 springcache 提供的 condition 条件,按条件缓存。

问题现象

预期的是查询外部系统有数据结果才会缓存account 与 uid得关系,uid结果为 null 得时候并不缓存。但是实际情况是uid有没有结果都不会缓存数据,不符合预期。

排查过程

思考点:

  1. 是不是对 condition 的条件缓存理解得有问题

代码分析

重点关注核心类 CacheInterceptor 拦截器里面对 @Cacheable 注解的解析

CacheInterceptor.invoke() ->CacheAspectSupport.execute() -> private execute()

从上面可知对 @Cacheable 注解的解析在第 2、3 和第 4 步,其中 condition 条件判断再第 2 以及 4 步。

其中第 2 步的findCachedItem 方法中的 conditon 用于判断是否从缓存中查询数据。

第 4 步中的collectPutRequest 方法中的 condition 用于判断是否要写入缓存,具体实现如下:

通过代码 debug ,发现步骤 2 以及步骤 4 中的 isConditionPassing 的返回值都是 false,因此当我们的配置 condition = "#result !==null' 的结果就是所有的数据都实时查询,查询结果也不会保存至缓存。

查阅资料

通过 spring 的docs.spring.io/spring-fram... 关于 springcache 的文档可知,conditon、unless条件是使用 SpEL 表达式实现的。

对于 condition 条件,只对入参进行判断,其中入参能使用的只有 #root 和参数,符合条件的查询入参可以

  • 查询走缓存
  • 缓存没有命中的时候,将实时查询的结果写入缓存

对于 unless 条件,只对出参进行判断,其中出参可以使用 #result 不符合条件的出参可以

  • 缓存没有命中的时候,将实时查询的结果写入缓存

因此,只要将 condition = "#result !==null' 这个条件改为 unless = "#result == null" 就能满足我们的预期:查询走缓存,如果返回结果为 null 则不写入缓存,否则将结果写入缓存。

总结

  1. @Cacheable 注解中,conditon 只对入参进行判断,符合条件的查询先走缓存,缓存没有命中的时候,将实时查询结果写入缓存,否则查询不走缓存并且结果不写入缓存
  2. @Cacheable 注解中,unless 只对出参进行判断,符合条件的不缓存,不符合条件的将结果写入缓存。

该问题的发生是因为自己对 spring cache 相关注解的原理没有深入了解,同时网上有一些错误的例子导致的,因此还是要多看看官方文档以及阅读源码。

相关推荐
通往曙光的路上8 分钟前
SpringIOC-注解
java·开发语言
一 乐17 分钟前
校园墙|校园社区|基于Java+vue的校园墙小程序系统(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·后端·小程序
TT哇18 分钟前
【面经 每日一题】面试题16.25.LRU缓存(medium)
java·算法·缓存·面试
青云交19 分钟前
Java 大视界 -- 基于 Java 的大数据联邦学习在跨行业数据协同创新中的实践突破
java·分布式计算·隐私保护·apache flink·大数据联邦学习·跨行业数据协同·安全通信
合作小小程序员小小店19 分钟前
桌面开发,在线%考试管理%系统,基于eclipse,java,swing,mysql数据库。
java·数据库·mysql·eclipse·jdk
oioihoii23 分钟前
C/C++混合项目中的头文件管理:.h与.hpp的分工与协作
java·c语言·c++
一瓢一瓢的饮 alanchan35 分钟前
Flink原理与实战(java版)#第2章 Flink的入门(第二节Flink简介)
java·大数据·flink·kafka·实时计算·离线计算·流批一体化计算
vx_bscxy32237 分钟前
告别毕设焦虑!Python 爬虫 + Java 系统 + 数据大屏,含详细开发文档 基于微信小程序的民宿预约系统22398 (上万套实战教程,赠送源码)
java·spring boot·mysql·微信小程序·课程设计
z_鑫1 小时前
Java线程池原理深度解析
java·开发语言·后端
春生野草1 小时前
启动Nginx
java·微服务·架构