PreparedStatement.setNull()插入NULL时必须指定与Oracle列类型精确匹配的java.sql.Types常量,如VARCHAR2用Types.VARCHAR、NUMBER(p,s)用Types.DECIMAL、TIMESTAMP WITH TIME ZONE用Types.TIMESTAMP_WITH_TIMEZONE,否则触发ORA错误。
PreparedStatement.setNull() 必须配对使用 SQL 类型常量
java 向 oracle 插入 null,不能只调用 setnull() 就完事——它要求第二个参数是 java.sql.types 中的类型常量,且该常量需与目标列的实际 sql 类型语义一致。oracle 对类型敏感,比如 varchar2 列传 types.integer 会报 ora-01722: invalid number,不是语法错,而是类型推导失败。
-
setNull(1, Types.VARCHAR)适用于VARCHAR2、CHAR列 -
setNull(1, Types.INTEGER)对应NUMBER(38)或NUMBER(10,0)等整数精度列 -
setNull(1, Types.DECIMAL)更稳妥于带小数的NUMBER(p,s)(如NUMBER(12,2)) - 日期列必须用
Types.DATE或Types.TIMESTAMP,混用会导致 ORA-01858
Oracle 的 NUMBER 类型到底该选 Types.INTEGER 还是 Types.DECIMAL
看列定义。Oracle 没有独立的 “integer” 类型,全靠 NUMBER 精度约束模拟。如果建表时写的是 score NUMBER(5,2),就得用 Types.DECIMAL;如果是 user_id NUMBER(10)(隐含 scale=0),Types.INTEGER 可用,但 Types.DECIMAL 更通用、更安全。
-
Types.INTEGER在某些 JDBC 驱动版本中可能被映射为NUMBER(10),遇到超长整数(如 11 位 ID)会截断或报错 -
Types.DECIMAL允许驱动保留完整精度,尤其配合setNull(int, int, String)重载时可传 scale 信息(虽极少用) - 实际项目中,统一用
Types.DECIMAL处理所有NUMBER列,出错率最低
setNull() 后 executeUpdate() 报 ORA-00932:类型不匹配的典型场景
这个错误往往不是 NULL 本身的问题,而是 JDBC 驱动在预编译阶段尝试“推测”参数类型失败。常见于使用了函数包装的占位符,比如:INSERT INTO t VALUES (UPPER(?))。此时你对 ? 调用 setNull(1, Types.VARCHAR),但 Oracle 认为 UPPER(NULL) 返回类型不确定,拒绝执行。
- 避免在占位符外加函数:改写成
INSERT INTO t(col) VALUES (?),让 NULL 直接进列 - 若必须函数处理,改用
COALESCE(?, '')等明确返回类型的表达式(但注意这会让 NULL 变成空字符串) - 检查是否误把
setString(1, null)当作 setNull() 使用——这会传 Java null 字符串,Oracle 解析为字面量'null',不是 SQL NULL
Oracle TIMESTAMP WITH TIME ZONE 列插入 NULL 的特殊处理
这类列不能直接用 Types.TIMESTAMP。Oracle JDBC 驱动对时区感知类型有额外要求,否则会抛 ORA-00932: inconsistent datatypes 或静默转成本地时区时间。
- 必须用
Types.TIMESTAMP_WITH_TIMEZONE,且驱动版本需 ≥ 12.1(旧版不支持) - 确认
ojdbc8.jar或更高版本已引入,低版本即使写了该常量也会 fallback 到Types.TIMESTAMP - 测试方法:插入后查出来看
TZ_OFFSET是否保留,而不是只看值是否为 NULL










