oracle将空字符串""视作null是其自上世纪80年代确立的固有行为,插入时自动转为null并触发非空约束报错,where条件中""恒不匹配,业务需用占位符绕过。

Oracle 把 "" 当成 NULL,不是 bug,是它从上世纪 80 年代就定下的行为,至今未改——你写 INSERT INTO t(x) VALUES (''),数据库底层直接转成 INSERT INTO t(x) VALUES (NULL),然后才校验约束。
ORA-01400 报错时,"" 其实已经没了
当你在 Java 里调用 setEmail(""),JDBC 驱动把空字符串发给 Oracle;Oracle 接收到后,立刻把它“归一化”为 NULL,不经过任何转换逻辑或配置开关。所以哪怕你确认日志里打印的是 "",到数据库层面它已经是 NULL,非空字段自然报 ORA-01400。
- 这个转换发生在 SQL 解析阶段,早于约束检查
- 无论用 JDBC、SQL*Plus、SQL Developer 还是 PL/SQL,结果都一样
-
CHAR类型也服从该规则(实测 Oracle 21c 仍如此)
WHERE col = '' 永远查不到数据
因为 '' 被视作 NULL,而 NULL = NULL 返回的是 UNKNOWN,不是 TRUE,所以整个条件恒为假。哪怕表里真有某行被插入了 ''(实际存的是 NULL),SELECT * FROM t WHERE col = '' 也一条不返回。
- 正确写法只能是
col IS NULL -
col ''同样无效,得写col IS NOT NULL - 如果业务上需要区分“空字符串”和“未填写”,Oracle 原生不支持——它根本没有空字符串这个值
别信“未来会改”,但可以绕过
Oracle 官方文档从 12c 到 21c 都写着:“Note: Oracle Database currently treats a character value with a length of zero as null. However, this may not continue to be true in future releases”。这句话十几年没变过,也没见哪版真正改掉。别等兼容性修复,得自己处理:
- 入库前把
""替换成占位符,比如"<empty>"</empty>或单空格" "(注意:单空格" "是合法非空字符串,不会被转成NULL) - Java 层统一用
StringUtils.defaultString(str, " ")替代裸"" - 应用层判断空值时,不要只看
str == null || str.isEmpty(),要意识到:从 Oracle 查出来的NULL字段,在 Java 里就是null,不是""
最麻烦的不是存不进去,而是“你以为存了空串,其实存了 NULL;你以为能用 = 比较,其实永远比不出结果”——这种隐式转换藏在每一层交互里,不翻源码、不看执行计划,根本发现不了。











