应先查询数据库实际字符集再配置NLS_LANG:执行SELECT VALUE FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET';若无权限则用SELECT USERENV('language') FROM DUAL提取点号后字符集;再按客户端类型分别设置NLS_LANG,最后通过NLS_SESSION_PARAMETERS验证生效。
直接看数据库字符集再配,别猜、别套模板——oracle 19c 默认用 al32utf8,但你连的库如果建库时选了 zhs16gbk,设成 al32utf8 就必然乱码。
先查清服务端真实字符集,不是“应该是什么”
登录数据库执行:
SELECT VALUE FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET';
返回值就是服务端实际使用的字符集,常见有 AL32UTF8 或 ZHS16GBK。注意:别信安装文档或同事说的“默认是 UTF8”,19c 兼容老库,很多迁移来的库仍是 ZHS16GBK。如果返回空或报错,说明没权限,换 SELECT USERENV('language') FROM DUAL; 看完整字符串,从中提取点号后的内容(如 SIMPLIFIED CHINESE_CHINA.ZHS16GBK → 字符集是 ZHS16GBK)。
按客户端类型分别设置NLS_LANG,不能一设全通用
NLS_LANG 不是全局开关,不同客户端读取方式完全不同:
- SQL*Plus(命令行):Linux/macOS 在 shell 启动文件中加
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8;Windows 命令行用set NLS_LANG=AMERICAN_AMERICA.ZHS16GBK,且必须在启动 SQL*Plus 前执行 - PL/SQL Developer:不读系统环境变量,必须进
Tools → Preferences → Oracle → Connection,手动填完整值,比如AMERICAN_AMERICA.ZHS16GBK - Python cx_Oracle(v8+):优先不设
NLS_LANG,让驱动自动协商;若需强制指定,用cx_Oracle.init_oracle_client(config_dir=...)配tnsnames.ora,比环境变量更稳 - JDBC 应用:完全忽略
NLS_LANG,必须在连接 URL 里加参数,例如?useUnicode=true&characterEncoding=UTF-8
验证是否生效,只看 NLS_SESSION_PARAMETERS
设完别急着查数据,先在 SQL*Plus 或 PL/SQL Developer 中运行:
SELECT PARAMETER, VALUE FROM NLS_SESSION_PARAMETERS WHERE PARAMETER IN ('NLS_LANGUAGE', 'NLS_TERRITORY', 'NLS_CHARACTERSET');
重点盯 NLS_CHARACTERSET 这一行的 VALUE,它才是当前会话实际生效的字符集。如果它和前面查到的数据库字符集不一致,说明配置没生效——常见原因是工具没重启、路径写错、漏了下划线或大小写拼错(AL32UTF8 不是 utf8)。
Windows 终端代码页不匹配,设对 NLS_LANG 也白搭
即使 NLS_LANG 设成了 AMERICAN_AMERICA.ZHS16GBK,如果 CMD 当前代码页是 65001(UTF-8),而终端本身不支持 GBK 渲染,照样显示方块。用命令 chcp 查当前页号:chcp 936 切到 GBK,chcp 65001 切到 UTF-8。Linux 终端同理,locale 输出里 LANG 必须和 NLS_LANG 的 CHARACTERSET 兼容(如 LANG=en_US.UTF-8 对应 AL32UTF8)。
最容易被忽略的是:同一个机器上,SQL*Plus、PL/SQL Developer、IDE 内嵌终端三者可能各自读取不同位置的 NLS_LANG,且互不影响。别指望改一次系统变量就全好,得逐个验证。











