mybatis默认将数据库null映射为java属性默认值:基本类型抛异常,包装类和string为null;需显式配置jdbctype并用包装类型才能正确处理null,default属性对null无效。

MyBatis 中 resultMap 遇到数据库字段为 NULL 时默认行为
MyBatis 默认会把数据库的 NULL 值映射为 Java 对象对应属性的默认值:基本类型用零值(如 0、false),引用类型(如 String、Integer)才可能为 null。但前提是你的 Java 字段声明是包装类或对象类型,且没配 jdbcType。
常见踩坑点:
- 字段声明为
String name,数据库值为NULL→ 映射后是null;若声明为String name = ""或有构造函数赋初值 → 可能被覆盖成null,也可能保留空字符串,取决于 setter 是否被调用 - 字段是
int age,数据库为NULL→ MyBatis 无法赋值给基本类型,抛出org.apache.ibatis.executor.result.ResultMapException - 没在
resultMap中显式指定jdbcType的可空列,某些 JDBC 驱动(如 older MySQL Connector/J)可能返回""而非null,造成语义混淆
如何让 NULL 和空字符串在映射后可区分?
关键在于两件事:一是告诉 MyBatis “这个字段允许为 NULL”,二是避免空字符串被误当作有效值覆盖掉原本的 null 意图。必须显式配置 jdbcType 并配合合理的 Java 类型设计。
- 在
resultMap中为可能为NULL的列加上jdbcType,例如:<result column="nick_name" property="nickName" jdbctype="VARCHAR"></result>
- Java 字段必须使用包装类型或
String,不能用int/boolean等基本类型 - 如果业务上需要区分 “数据库 NULL” 和 “数据库存了空字符串”,仅靠 MyBatis 默认映射做不到 —— 它俩都会变成 Java 的
null或""。此时需在 SQL 层做转换,比如:SELECT id, CASE WHEN nick_name IS NULL THEN '__NULL__' ELSE nick_name END AS nick_name FROM user
,再在 Java 层解析标记
MyBatis 的 default 属性对空值无效
<result></result> 标签的 default 属性**只在列名不存在或 ResultSet 无该列时生效**,它不处理 NULL 值。很多人误以为写 default="" 就能让 NULL 变成空字符串,实际完全不起作用。
真正可控的方式只有两种:
- 在 SQL 中用
COALESCE(nick_name, '')或IFNULL(nick_name, '')强制转空字符串 - 在 Java Bean 的 getter 中统一处理,例如:
public String getNickName() { return nickName == null ? "" : nickName; }
Spring Boot + MyBatis-Plus 场景下的额外注意
MyBatis-Plus 的自动填充、逻辑删除、以及 @TableField(fill = ...) 都依赖字段是否为 null 判断是否触发。如果数据库字段允许 NULL,但你又在实体类里写了 private String remark = "";,那么即使查出来是 NULL,也会被初始化为空字符串,导致自动填充失效或条件判断出错。
建议做法:
- 所有可能为
NULL的字段,Java 层不做默认初始化,保持private String remark; - 启用 MyBatis-Plus 的
configuration.call-setters-on-nulls=true(默认 false),确保NULL也会调用 setter,便于后续逻辑统一处理 - 若用
@TableField(strategy = FieldStrategy.IGNORED),要清楚它跳过的是“非空判断”,不是“NULL 判断”——字段为null仍会参与更新,除非你手动设为FieldStrategy.NOT_EMPTY










