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 test="score > 0">,当 score 为 null 时,OGNL 表达式会直接报错(NPE)。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- ✅ 正确写法:
<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">
自定义 TypeHandler 应对特殊场景
多数情况无需自定义,但在以下场景建议实现 BaseTypeHandler<T>:
- 数据库用
TINYINT(1)存布尔逻辑(0/1),但 Java 想映射为Boolean(而非Integer) - 需要把数据库
NULL统一转为某个默认对象(如BigDecimal.ZERO),或反向把null写成0(慎用,违背可空语义) - 字段含业务级空值含义(如 -999 表示“未填写”),需在读写时做转换
注册方式(XML 配置):
<typeHandlers>
<typeHandler handler="com.example.BooleanTinyIntHandler" javaType="java.lang.Boolean" jdbcType="TINYINT"/>
</typeHandlers>
实体类设计建议:显式区分“未设置”与“零值”
例如用户年龄字段:Integer age 能清晰表达 “未知(null)” vs “0岁(明确为零)”。若用 int age = 0,就丢失了语义区分能力。
- 所有可能为空的数值字段,一律用包装类
- 构造器、Builder 或 Lombok 的
@Builder中,不给包装类字段设默认值(如避免private Integer score = 0;) - DTO 层若需兼容前端传参,可用
@JsonInclude(JsonInclude.Include.NON_NULL)控制序列化
不复杂但容易忽略。核心就三点:用包装类、别在 OGNL 里对 null 直接运算、特殊需求再动 TypeHandler。

















