起因
在某个入参为map的方法上加了@Cacheable注解后,测试传入空json(在mapper业务逻辑里面传入空json是搜全表)时,报错:Null key returned for cache operation
网上查了各种解决方案,挺多都是说SPEL解析式解析key值出问题啥的,有点像是底层问题,而框架底层代码我一个小白是不敢动的,就非常抓狂。网上找到的的解决方法:
- 改@Cacheable注解的入参为p1p2之类的
- 给编译加-parameters参数的(不推荐)
- 炫技类自己写key generator
不过最后结合我自己的情况,加上同事的指导,以上的解决方案我都不需要。
我只需要在controller加一个数据预处理就好了。
把我的解决过程发出来记录分享下~希望能帮助到跟我一样抓狂的小白
代码结构描述
Map<String, String> {//仅描述
"XXX" : "xxx"
}
//Controller
public class XXXColtroller {
public ControllerRetType getXXX (@RequestBody Map<String, String> map) {
......
ServiceRetType serviceRetVal = XXXService.getXXX(map);
......
}
}
//Service
public class XXXService {
@Cacheable(value = "XXXCache", key = "#map[XXX]")//重要
public ServiceRetType getXXX (Map<String, String> map) {
......
MapperRetType mapperRetVal = XXXMapper.getXXX(map);
......
}
}
<!-- XXXXMapper.xml中getXXX的sql描述 -->
<!-- sql逻辑:当XXX为null时,就会查全表 -->
<select id="getXXX" resultType = "java.util.HashMap"
parameterType = "java.util.HashMap">
select * from XXTable a where 1 = 1
<if test="XXX != '' and XXX != null">
AND a.XXX = #{XXX}
</if>
</select>
Bug产生过程:Postman构造json测试
- 当json含有 {“XXX” : “xxx”}时,可以顺利查出来,也能成功缓存,因为这个时候缓存的key (就是#map[XXX])是存在的。
- 当json不含有"XXX"这个key时,如json={},本来要的效果是查全表,结果直接报错:Null key returned for cache operation
Bug原因分析
就如代码提供的错误信息:Null Key,service的入参map中根本没有"XXX"这个key,那自然就是null key。
如何解决?
方法1:绕开key为null的情况
仅需给上文的@Cacheable注解添加一个参数:
@Cacheable(value = "XXXCache", key = "#map[XXX]", condition = "#map[XXX] != null")
效果:当请求的map参数没有"XXX"这个key的时候(#map[XXX] = null),不走缓存,直接走数据库查询。
不满足condition条件的情况,@Cacheable不会处理,那么就自然不会报错啦~
方法2:对空值做预处理
具体到本次情况,当入参map不含有"XXX"的key时,我们在Controller手动给它赋一个初值~
方法2相比方法1的好处在于,key为null时也可以缓存了,等于说所有状况都可以缓存。
public class XXXColtroller {
public ControllerRetType getXXX (@RequestBody Map<String, String> map) {
......
map.putIfAbsent("XXX", "");//对空值做预处理
ServiceRetType serviceRetVal = XXXService.getXXX(map);
......
}
}