jdbc中getint()等基础类型方法遇null返回0而非null,需用wasnull()判断或getobject("age", integer.class)获取真实null;设计上应避免整型字段存null。

当 JDBC 查询含空值(NULL)的整型字段(如 INT、TINYINT、SMALLINT)时,ResultSet.getXXX() 方法(如 getInt()、getShort())会**自动将 NULL 转为 0 或 false**,而非返回 null。这在业务逻辑中极易引发误判——比如把“未填写年龄”和“年龄为 0 岁”混为一谈。排查与规避需从 JDBC 行为本质出发,不能只靠事后校验。
理解 JDBC 的隐式转换规则
JDBC 规范明确要求:getInt()、getShort()、getLong() 等基础类型 getter 方法,遇到 SQL NULL 时必须返回该类型的 Java 默认值(0 或 false),且不抛异常。这不是 Bug,而是设计契约。因此:
-
rs.getInt("age")返回 0,无法区分是数据库存了 0,还是存了 NULL -
rs.wasNull()是唯一官方配套机制:它必须紧跟在getXXX()之后调用,才能确认上一次取值是否为 NULL -
rs.getObject("age", Integer.class)可返回 null(JDBC 4.1+),但需驱动支持且字段映射为可空包装类型
优先使用 wasNull() 显式判断
这是最轻量、最兼容的修复方式,无需改表结构或驱动参数:
- 每次调用
getInt()后立即检查rs.wasNull() - 若为 true,则按业务逻辑处理空值(如设为 null、跳过赋值、填默认值等)
- 示例:int age = rs.getInt("age"); if (rs.wasNull()) { user.setAge(null); } else { user.setAge(age); }
改用 getObject + 包装类型获取真实 null
绕过基础类型强制转换,直接获取对象引用:
- 推荐写法:
Integer age = rs.getObject("age", Integer.class) - 该方法在字段为 NULL 时返回 null,在非 NULL 时自动装箱为 Integer
- 注意:旧版 MySQL 驱动(如 mysql-connector-java 5.x)对
TINYINT(1)有特殊处理(映射为 Boolean),若字段本意是数字而非布尔,需在连接 URL 加?tinyInt1isBit=false - 验证驱动行为:执行
rs.getMetaData().getColumnTypeName(i)确认实际 JDBC 类型是否为INTEGER而非BIT
源头治理:避免整型字段存 NULL
对新表或可重构场景,从数据库设计层面减少歧义:
- 业务上允许“未知”的整型字段,考虑用特殊值替代(如 -1、9999),并在代码/文档中明确定义
- 若必须保留 NULL,建议在建表时添加注释,例如:
age INT COMMENT '年龄,NULL 表示未提供' - 配合 MyBatis 等框架时,使用
<result column="age" property="age" javatype="java.lang.Integer"></result>显式指定包装类型










