Oracle中文乱码源于数据库字符集、客户端NLS_LANG、应用层编码三者未对齐;须先查清数据库真实字符集(AL32UTF8或ZHS16GBK),再按客户端类型严格配置NLS_LANG为LANGUAGE_TERRITORY.CHARACTERSET格式,并验证NLS_SESSION_PARAMETERS中NLS_CHARACTERSET是否匹配。

Oracle中文乱码不是单一问题,而是三处字符集没对齐的结果:数据库字符集、客户端NLS_LANG、应用层编码。只要其中一处错位,就会出现问号、方块或错字。
查清数据库真实字符集,别猜
连上数据库后立刻执行:
SELECT VALUE FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET';
结果只认两个值:AL32UTF8(UTF-8)或ZHS16GBK(GBK)。其他如US7ASCII或WE8ISO8859P1基本不支持中文,不能用于含中文的业务库。别信安装文档写的“默认UTF-8”,生产库常是ZHS16GBK。
- 如果返回
ZHS16GBK,所有客户端必须配成AMERICAN_AMERICA.ZHS16GBK,不能混用AL32UTF8 - 如果返回
AL32UTF8,客户端可配AMERICAN_AMERICA.AL32UTF8,但注意JDBC驱动不依赖NLS_LANG,得靠连接串参数 -
NLS_NCHAR_CHARACTERSET查的是NVARCHAR2字段用的字符集,一般也是AL32UTF8,和主字符集无关,别混淆
SQL*Plus / PL/SQL Developer 连接时乱码
这类工具严格认NLS_LANG,但设置方式不同:
- SQL*Plus:在启动前设环境变量,Linux/macOS用
export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK,Windows用set NLS_LANG=AMERICAN_AMERICA.ZHS16GBK;设完必须新开终端,旧会话不生效 - PL/SQL Developer:不读系统变量,要去
Tools → Preferences → Oracle → Connection里手动填NLS_LANG值,填错一个字母(比如AMERIAN)就失效 - 别在
$ORACLE_HOME/sqlplus/admin/glogin.sql里写SET NLS_*命令——它只影响会话级参数,不改变字符集协商逻辑
Python cx_Oracle 插入中文失败
cx_Oracle v8+ 默认走Unicode路径,但底层仍走OCI,NLS_LANG设错会触发隐式转换,导致插入变问号。
- 优先不设
NLS_LANG,让驱动自动协商;若出错,再显式指定,格式必须是LANGUAGE_TERRITORY.CHARACTERSET(如AMERICAN_AMERICA.AL32UTF8) - 连接后立刻检查:
conn.encoding和conn.nencoding——前者对应VARCHAR2,后者对应NVARCHAR2;若与数据库NLS_CHARACTERSET不一致,说明协商失败 - 避免手动转码:
str.encode('gbk').decode('utf-8')这类操作对cx_Oracle无效,反而引入二次乱码 - 生僻字(如「䶮」「㼆」)建议存到
NVARCHAR2字段,并用n'...'前缀插入,例如INSERT INTO t VALUES (n'䶮')
SQL Developer 导出SQL文件后打开是问号
这是导出编码与编辑器解码不匹配,不是数据库问题。
- 导出时在
Export Wizard里选File Encoding:若数据库是ZHS16GBK,选GBK;若是AL32UTF8,选UTF-8 with BOM(不是“UTF-8”) - 纯
UTF-8无BOM,VS Code/Notepad++常默认按系统编码(Windows是GBK)打开,必然乱码;加BOM才能被正确识别 - 导出后用
file -i xxx.sql(Linux/macOS)或PowerShell的Get-Content xxx.sql -Encoding UTF8验证实际编码
最容易被忽略的是:NLS_LANG只管传输时的字节解释,不管字体渲染。安装界面中文显示方块?那是JRE缺中文字体,跟NLS_LANG完全无关——得去jre/lib/fonts里塞simhei.ttf并重命名为LucidaSans.ttf。


















