mybatis 返回 null 的根本解法是分层拦截与语义明确:mapper 层强制返回非 null 集合(如 list),service 层对单对象用 optional 包装,controller 层统一返回 collections.emptylist(),并启用 callsettersonnulls 确保 null 字段可安全映射。

MyBatis 返回 null 是常见但可控的问题,关键不在“堵”,而在“疏”——提前明确语义、统一约定、分层拦截。最稳妥的做法是:让空值不落地、不传递、不裸用。
Mapper 层:强制返回集合,禁用 null 结果
MyBatis 默认对 selectList 类型方法保证返回非 null 集合(空 ArrayList),但前提是接口声明必须是 List<t></t>,不是 T 或 Object。若写成:
-
User selectById(Long id);→ 查不到就返回null,高危 -
List<user> selectById(Long id);</user>→ MyBatis 自动返回Collections.emptyList(),安全
即使业务上“只查一个”,也建议用 List<user> selectById(Long id)</user> + get(0)(配合判空或 stream().findFirst()),避免 null 透传。
Service 层:对单对象查询做 Optional 包装
当确实需要返回单个对象(如 selectOne 或主键查询),不要让 Controller 直接接收 null。应在 Service 层兜底:
return Optional.ofNullable(userMapper.selectByPrimaryKey(id));- 调用方用
.orElse(null)、.orElseThrow()或.ifPresent()显式处理分支,语义清晰 - 避免
Optional.get()—— 它和直接用user.xxx()一样危险
Controller 层:空集合统一用 Collections.emptyList()
Controller 返回 JSON 时,若数据为空,别 new ArrayList(),直接用:
return ResponseEntity.ok(Collections.emptyList());- 它内存零开销、线程安全、不可变,Jackson 序列化结果仍是
[] - 比 new 出来再清空更轻量,也避免后续误 add() 导致
UnsupportedOperationException
XML / 注解配置:启用 callSettersOnNulls
当使用 resultType="hashmap" 或自定义 Map 封装时,数据库字段为 NULL 可能导致 key 缺失,引发 NPE。在 Spring Boot 中添加:
mybatis.configuration.call-setters-on-nulls=true- 这样 MyBatis 会把
NULL字段也 put 进 Map,值为null,便于后续用Objects.nonNull()或Map.getOrDefault()安全处理
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











