在 linux 上用 sqlplus @xxx.sql 执行脚本时,只要 sql 文件里有中文字符串或中文注释,就可能遇到乱码。这个问题通常不是数据库本身坏了,而是 sql 文件编码、linux locale、sql*plus 客户端字符集没有对齐。
先看清三个关键角色
执行 sql 文件时,至少涉及三处字符集:
- linux locale:由
lang或lc_ctype控制,影响 shell 如何处理文本。 - sql*plus 客户端字符集:由
nls_lang控制。 - sql 文件实际编码:常见是 utf-8 或 gbk。
核心原则很简单:
sql 文件编码要和
nls_lang对应的客户端字符集一致,再由 oracle 负责客户端与数据库之间的字符集转换。
这里最容易误解的是:nls_lang 表示客户端字符集,不是数据库字符集。
utf-8 文件的推荐配置
大多数 linux 环境和编辑器默认已经使用 utf-8,因此更推荐统一使用 utf-8。
export lang=en_us.utf-8 export nls_lang=american_america.al32utf8
如果使用中文 locale,也可以是:
export lang=zh_cn.utf-8 export nls_lang=simplified chinese_china.al32utf8
sql 文件建议保存为:
- utf-8
- 无 bom,也就是 utf-8 without bom
如果 sql 文件本身是 gbk 编码,才使用:
export lang=zh_cn.gbk export nls_lang=simplified chinese_china.zhs16gbk
不要盲目照抄数据库字符集
很多人看到数据库字符集是 zhs16gbk,就直接设置:
export nls_lang=simplified chinese_china.zhs16gbk
这只有在客户端 sql 文件本身也是 gbk 编码时才合适。
如果 sql 文件是 utf-8,而数据库字符集是 zhs16gbk,客户端仍然应该按 utf-8 设置:
export nls_lang=american_america.al32utf8
此时 oracle 会完成字符集转换:
utf-8(客户端)
↓
oracle character conversion
↓
zhs16gbk(数据库)
所以排查时不要只盯数据库字符集,更要先确认 sql 文件到底是什么编码。
如何确认文件和数据库字符集
查看 sql 文件编码,优先用:
file test.sql file -i test.sql
如果输出中看到 charset=utf-8,说明是 utf-8。若显示 utf-8 unicode (with bom),说明文件带 bom。
也可以用 iconv 验证 utf-8 是否合法:
iconv -f utf-8 -t utf-8 test.sql >/dev/null echo $?
返回 0 表示合法 utf-8;如果出现 illegal input sequence,说明不是合法 utf-8。
检查是否带 bom:
xxd -l 16 test.sql
如果文件开头出现:
ef bb bf
说明带 bom。
数据库字符集可以用 sql 查询:
select value from nls_database_parameters where parameter = 'nls_characterset';
常见结果可能是 al32utf8 或 zhs16gbk。
lc_all 不一定要设置
通常不需要刻意设置 lc_all。locale 优先级大致是:
lc_all ↓ lc_* ↓ lang
sql*plus 中文乱码更相关的是:
langlc_ctypenls_lang
很多环境只设置下面这一项就够了:
export lang=en_us.utf-8
lc_all 是强制覆盖所有 locale 设置,并不是解决 sql*plus 中文乱码的关键。有些系统还可能没有安装对应 locale,导致 cannot change locale。可以先确认系统支持项:
locale -a
一套稳妥排查顺序
遇到乱码时,建议依次执行:
locale echo $lang echo $nls_lang file -i test.sql
再查数据库字符集:
select value from nls_database_parameters where parameter='nls_characterset';
笔者更推荐的长期做法是:团队统一使用 utf-8 无 bom 的 .sql 文件,并配置:
export lang=en_us.utf-8 export nls_lang=american_america.al32utf8
这样可以减少 utf-8、gbk 混用带来的跨平台问题。
一句话总结:保持 sql 文件编码、linux locale 和 nls_lang 一致,让 oracle 负责客户端与数据库之间的字符集转换,是避免 sql*plus 中文乱码的稳妥方案。
到此这篇关于linux下用sql*plus执行中文sql文件时如何避开乱码坑的文章就介绍到这了,更多相关sql*plus中文乱码解决内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论