MyBatis查询返回List时偶发返回null而非空列表触发NPE问题咨询
MyBatis查询偶发返回null而非空列表的原因及解决方案
核心原因分析
MyBatis官方默认逻辑中,返回值为List类型的查询如果无匹配结果,一定会返回空列表而非null,出现该问题大概率是以下场景导致的:
- 依赖版本存在BUG
如果你使用的是3.4.0之前的MyBatis版本,或者搭配了低版本的分页插件(如PageHelper 5.0之前的部分版本),存在已知的返回值处理漏洞:当查询参数异常、分页参数非法时,插件会篡改MyBatis的默认返回逻辑,直接返回null。 - 自定义组件篡改返回值
如果你配置了自定义的MyBatis拦截器、ResultHandler,或者给Mapper层加了自定义切面,可能存在逻辑漏洞:在处理无结果的返回值时误将空列表赋值为null。 - 二级缓存存在脏数据
如果你开启了MyBatis二级缓存,且之前某次查询因为异常(如事务回滚、sql执行出错后被异常捕获)将null值写入了缓存,后续相同查询会直接命中缓存返回null,不会触发实际SQL执行。 - ResultMap映射逻辑异常
如果你自定义的ClientAccessResult结果映射中配置了强制校验规则,当查询到的行数据有字段不满足映射规则时,部分特殊的类型处理器会直接返回null而非跳过该行,最终导致整个结果集被赋值为null。
临时修复方案
在校验前先做null值兼容处理,代码示例:
final List<ClientAccess> clientAccesses = Optional.ofNullable( clientAccessMapper.findByClientAndPartnerWithAutoRenewal(client, partner, true) ).orElse(Collections.emptyList()); if (clientAccesses.isEmpty()) { // 原有逻辑 }
根因排查建议
- 先关闭二级缓存测试是否复现,排除缓存脏数据问题
- 升级MyBatis及相关插件到最新稳定版,排除版本BUG
- 排查所有Mapper层的拦截器、切面逻辑,校验返回值处理部分是否存在空值赋值漏洞
内容的提问来源于stack exchange,提问作者Maksym Rybalkin
相关产品推荐
相关产品推荐

