mybatis天然支持包装类与数据库可空字段映射,关键在于:实体字段必须用integer等包装类而非int;xml中判空需用“score != null”避免npe;特殊场景(如tinyint转boolean)可自定义typehandler。

Java 包装类(如 Integer、Long、Boolean 等)与数据库中可空数值字段(如 INT NULL、TINYINT NULL)的映射,在 MyBatis 中天然支持,但需注意几个关键点才能避免 NullPointerException、默认值误设或类型不匹配问题。
MyBatis 默认能正确映射包装类与 NULL 值
MyBatis 使用反射 + 类型处理器(TypeHandler)自动处理基本类型和包装类。对可空字段(如数据库中 score INT NULL),若查出为 NULL,MyBatis 会将结果映射为 Integer null(而非 0);插入/更新时若 Java 字段为 null,MyBatis 也会向数据库写入 NULL —— 这是默认行为,无需额外配置。
前提是:实体类字段必须使用包装类(Integer),不能用基本类型(int)。否则 MyBatis 无法表示“空”,会抛异常或静默转为默认值(如 0)。
避免在 XML 中误用基本类型导致空指针
在 MyBatis 的 XML 映射文件中,如果用 <if test="score != null"></if> 判断包装类字段,这是安全的;但若写成 <if test="score > 0"></if>,当 score 为 null 时,OGNL 表达式会直接报错(NPE)。
- ✅ 正确写法:
<if test="score != null">AND score = #{score}</if> - ❌ 危险写法:
<if test="score > 0">AND score > #{score}</if>(null 参与比较会 NPE) - ? 安全替代:
<if test="score != null and score > 0"></if>
自定义 TypeHandler 应对特殊场景
多数情况无需自定义,但在以下场景建议实现 BaseTypeHandler<t></t>:
- 数据库用
TINYINT(1)存布尔逻辑(0/1),但 Java 想映射为Boolean(而非Integer) - 需要把数据库
NULL统一转为某个默认对象(如BigDecimal.ZERO),或反向把null写成0(慎用,违背可空语义) - 字段含业务级空值含义(如 -999 表示“未填写”),需在读写时做转换
注册方式(XML 配置):
实体类设计建议:显式区分“未设置”与“零值”
例如用户年龄字段:Integer age 能清晰表达 “未知(null)” vs “0岁(明确为零)”。若用 int age = 0,就丢失了语义区分能力。
- 所有可能为空的数值字段,一律用包装类
- 构造器、Builder 或 Lombok 的
@Builder中,不给包装类字段设默认值(如避免private Integer score = 0;) - DTO 层若需兼容前端传参,可用
@JsonInclude(JsonInclude.Include.NON_NULL)控制序列化
不复杂但容易忽略。核心就三点:用包装类、别在 OGNL 里对 null 直接运算、特殊需求再动 TypeHandler。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











