存储过程传入参数乱码90%因客户端字符集未正确配置,须先查数据库字符集select value from nls_database_parameters where parameter='nls_characterset',再按客户端类型配置nls_lang或jdbc charset参数确保严格一致。

存储过程传入参数乱码,90%不是存储过程写错了,而是客户端没把字符集“说清楚”——NLS_LANG没设对,或 JDBC 没显式传 charset。
查清数据库和服务端实际用的字符集
别猜,直接查。参数乱码的前提是服务端编码和客户端解码不匹配,必须先确认底座:
-
SELECT value FROM nls_database_parameters WHERE parameter = 'NLS_CHARACTERSET';—— 返回如AL32UTF8或ZHS16GBK,这是硬性约束,不能靠会话覆盖 -
SELECT value FROM nls_session_parameters WHERE parameter = 'NLS_CHARACTERSET';—— 看当前连接实际生效的会话字符集,它可能被NLS_LANG或 JDBC 参数覆盖 - 如果两者不一致(比如数据库是
ZHS16GBK,但会话显示US7ASCII),说明客户端根本没协商成功,参数传进去就是错字节
JDBC 调用存储过程时必须显式设 charset
Oracle JDBC 驱动(ojdbc8.jar 及以上)完全不读系统 NLS_LANG 环境变量,靠它传中文参数必然乱码。
- 错误写法:
props.put("NLS_LANG", "AMERICAN_AMERICA.AL32UTF8")—— JDBC 忽略此键,纯无效 - 正确写法:
props.put("charset", "AL32UTF8")(值必须和数据库NLS_CHARACTERSET严格一致) - Spring Boot 用户:用
spring.datasource.hikari.data-source-properties.charset=AL32UTF8,比拼 URL 更可靠 - URL 中加
characterEncoding=UTF-8是无效的——Oracle 不认这个参数,只认charset键
PL/SQL Developer 或 SQL*Plus 里调用要手动对齐字符集
图形工具常“自动选字符集”,反而掩盖问题;命令行更脆,错一个字符就全崩。
- PL/SQL Developer:菜单
Tools → Preferences → Oracle → Connection → Character set,必须手动选成和数据库一致的项(如ZHS16GBK),不能留空或选“Auto” - SQL*Plus 命令行(Windows):
set NLS_LANG=AMERICAN_AMERICA.ZHS16GBK必须三段齐全、顺序固定;只写ZHS16GBK会被忽略 - 验证是否生效:连上后立即执行
SELECT * FROM nls_session_parameters WHERE parameter = 'NLS_CHARACTERSET';,结果必须和数据库一致 - 注意:Instant Client 启动脚本(如
plsqldev.bat)里硬编码的set NLS_LANG=...会覆盖系统环境变量,优先检查它
生僻字或超范围汉字需改用 NVARCHAR2 + N' 前缀
如果数据库字符集是 ZHS16GBK,但参数含“䶮”“㼆”等 Unicode 扩展区汉字,VARCHAR2 字段根本存不下——这不是乱码,是截断或替换。
- 存储过程参数类型得声明为
IN p_name NVARCHAR2,而不是VARCHAR2 - 调用时字符串必须加
N'前缀:EXEC my_proc(N'张学?䄲友'),否则 Oracle 当作VARCHAR2解析,生僻字直接丢 - 对应地,Java 侧要用
CallableStatement.setString()传入,驱动会自动处理NCHAR绑定;不要自己做new String(bytes, "GBK")这类手动转码
真正容易被忽略的是:NLS_LANG 的三段格式(LANGUAGE_TERRITORY.CHARACTERSET)缺一不可,且大小写敏感;JDBC 的 charset 值必须和 nls_database_parameters 完全一致,差一个字母(比如 UTF8 vs AL32UTF8)都会失败。











