- 循序渐进Oracle:数据库管理、优化与备份恢复
- 盖国强
- 892字
- 2020-06-26 12:09:27
3.10 “靠”字的困惑
讨论过乱码的产生原因之后,很多朋友可能会想起“靠”字的困惑。很多人可能都遇到过查询返回一连串“靠”字的经历,其根本原因同样是由于字符集的原因导致的乱码。
我们通过测试来研究一下这种情况,测试开始之前首先区分测试中将会涉及的几个字符即相关应用。
客户端应用字符集(Client Application Character Set)。
测试客户端应用使用命令行工具(cmd.exe),这个工具的字符集决定查询结果在终端上的输出显示,当前命令行工具的字符代码页为936,对应的是GBK字符集:
图3-11 命令行工具的字符集
客户端NLS_LANG参数设置。
为了测试异常情况,我们设置NLS_LANG为AMERICAN_AMERICA.WE8ISO8859P1。
D:\>SET NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1
服务器端,数据库字符集(Character Set)设置。
数据库的字符集为ZHS16GBK。
首先在数据库上创建一个测试表,存储一点中文数据:
SQL> create table tcharset (name varchar2(20));
SQL> insert into tcharset values('循序渐进深入浅出');
SQL> commit;
SQL> select * from tcharset;
NAME
--------------------
循序渐进深入浅出
然后在客户端WE8ISO8859P1字符集下执行查询:
D:\>SET NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1
D:\>sqlplus eygle/eygle@eygle
SQL*Plus: Release 10.2.0.3.0 - Production on Tue Jun 26 10:51:45 2007
Copyright (c) 1982, 2006, Oracle. All Rights Reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning option
JServer Release 9.2.0.4.0 - Production
SQL> select * from tcharset;
NAME
--------------------
靠靠靠靠
这里8个汉字被转换成了4个“靠”字输出显示?这是怎么回事呢?首先我们知道,Oracle数据库服务器是传输代码给客户端的,数据本身不存在问题,编码会原样传输到客户端:
SQL> select name,dump(name) from tcharset;
NAME
--------------------
DUMP(NAME)
--------------------------------------------------------------------------------
靠靠靠靠
Typ=1 Len=16: 209,173,208,242,189,165,189,248,201,238,200,235,199,179,179,246
那么可以确认存在问题的只是中间发生的转换环节。由于WE8ISO8859P1是8位的单Byte编码方案,所以中文汉字编码在其中不存在对应关系,也就是无法转换,此时WE8ISO8859P1字符集会使用一个替换字符来代替中文,这个替换字符是“¿”,也就是一个倒过来的“?”,不同字符集的替换字符,我们可以通过Locale Builder工具打开字符文件查看:
图3-12 字符集WE8ISO8859P1的替换字符
注意,这个特殊字符的编码为BF,那么也就是说,如果无法转换ZHS16GBK的8个中文字, WE8ISO8859P1将使用8个“¿”来替换,也就是说经过转换之后,有了8个BF的编码,那么我们再来看看8个BF在客户端的GBK字符集里代表了什么。
通过微软网站上的936代码页我们可以找到如图3-13所示的图表。
图3-13 GBK的字符编码页
936代码页的网址链接为http://www.microsoft.com/globaldev/reference/dbcs/936.htm。
从图3-14中可以看到,其中BFBF正好代表汉字“靠”,于是8个BF最后展现出来就变成了4个“靠”字。我们也可以通过ZHS16GBK字符集文件来找到这个编码,两者是一致的。
图3-14 字符集的编码
这也就是不同字符集、应用之间转换会导致的字符集问题。