昵称输入限制 20 个字符,用户填了 12 个汉字,校验通过,insert 时报 ORA-12899: value too large for column NICKNAME (actual: 36, maximum: 20)。第一次遇到会往复杂处想,其实漏掉的多是个小前提。

SELECT column_name, data_length, char_length, char_used
FROM user_tab_columns
WHERE table_name = 'USERS' AND column_name = 'NICKNAME';

Oracle 的 VARCHAR2(20) 默认按字节计,UTF-8 下一个汉字占 3 字节,12 个汉字就是 36 字节。应用层的 @Size(max=20) 按字符数算,所以放行。两边对长度的单位定义不一致,越靠后的字符集变更越容易踩到。这一点先确认清楚,后面就不用反复试。

「字符长度与字节长度」相关的日志我一般连着看前后五分钟,单看一条报错经常判断不出是哪一步失败。新版本先放一台机器上跑一天再全量,问题一般在这段时间暴露。

备份不是备了就行,恢复一次才算数,很多备份文件打开才发现是空的。接口问题先分清是没发出去、发出去了没收到,还是收到了处理失败。

具体做法是,查 user_tab_columns 确认 char_used 是 B 还是 C;把字段改成 VARCHAR2(20 CHAR) 或者在 DDL 里显式写 CHAR;应用层再加一条按字节的上限校验 兜住其它库;用同样的 12 个汉字重新提交一次。

改完照着核一遍,字段改成按字符计后 12 个汉字能正常写入 不再报 ORA-12899 长度也显示 20。

作者 9823189