本文将通过实验来演示一下Oracle字符集“转码”的确认过程。
曾经分享过的有关字符集文章如下:
《查看本地windows的字符集方法》
http://space.itpub.net/519536/viewspace-580610
《【字符集】“客户终端字符集”、“NLS_LANG”环境变量以及“数据库字符集”》
http://space.itpub.net/519536/viewspace-615345
《【字符集】处理Toad显示乱码及Windows XP下无法插入“某些汉字”问题》
http://space.itpub.net/519536/viewspace-615379
OK,现在开始我们的实验之旅。
1.实验环境说明
客户端是Windows XP操作系统的SQL*Plus程序,客户端字符集是936(对应Oracle的ZHS16GBK字符集);
数据库版本是Oracle 10g,数据库字符集是AL32UTF8;
NLS_LANG参数将在实验中进行指定。
1)确认客户端字符集
C:\>chcp
活动代码页: 936
注释:936对应Oracle的ZHS16GBK字符集。
2)查看数据库版本信息:
sec@ora10g> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
PL/SQL Release 10.2.0.3.0 - Production
CORE 10.2.0.3.0 Production
TNS for Linux: Version 10.2.0.3.0 - Production
NLSRTL Version 10.2.0.3.0 - Production
3)确认数据库的字符集:
sec@ora10g> col PARAMETER for a20
sec@ora10g> col value for a20
sec@ora10g> select * from v$nls_parameters where parameter = 'NLS_CHARACTERSET';
PARAMETER VALUE
-------------------- --------------------
NLS_CHARACTERSET AL32UTF8
2.实验中将会涉及到的两种场景
“转码”场景:设置客户端的NLS_LANG与客户端字符集一致,这里是ZHS16GBK;
“非转码”场景:设置客户端的NLS_LANG与数据库服务器端字符集一致,此处是AL32UTF8.
关于如何设置NLS_LANG参数,请参考下面文章:
《【NLS_LANG】不同操作系统平台NLS_LANG环境变量的查看与设置方法》
http://space.itpub.net/519536/viewspace-580623
在这个实验中,为了方便,我将采用set命令设置字符集。您可以按照自己的习惯去设置。
3.创建实验表T
sec@ora10g> create table t (x number(1), client_characterset varchar2(10), nls_lang varchar2(10), database_characterset varchar2(10), y varchar2(10));
Table created.
sec@ora10g> desc t;
Name Null? Type
----------------------------------- -------- ------------------------
X NUMBER(1)
CLIENT_CHARACTERSET VARCHAR2(10)
NLS_LANG VARCHAR2(10)
DATABASE_CHARACTERSET VARCHAR2(10)
Y VARCHAR2(10)
T表包含五个字段,分表表示序号、客户端字符集、客户端NLS_LANG设置情况以及数据库服务器字符集设置情况。
4.两种NLS_LANG设置方法下分别插入一条数据
1)当客户端的NLS_LANG设置为ZHS16GBK时,我们插入第一条记录(“转码”场景)。
C:\>set nls_lang=AMERICAN_AMERICA.ZHS16GBK
C:\>sqlplus sec/sec@ora10g
SQL*Plus: Release 10.2.0.3.0 - Production on Fri Feb 5 19:21:31 2010
Copyright (c) 1982, 2006, Oracle. All Rights Reserved.
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bit Production
With the Partitioning and Data Mining options
sec@ora10g> insert into t values (1,'ZHS16GBK','ZHS16GBK','AL32UTF8','圣');
1 row created.
sec@ora10g> commit;
Commit complete.
2)当客户端的NLS_LANG设置为AL32UTF8时,我们插入第二条记录(“非转码”场景)。
C:\>set nls_lang=AMERICAN_AMERICA.AL32UTF8
C:\>sqlplus sec/sec@ora10g
SQL*Plus: Release 10.2.0.3.0 - Production on Fri Feb 5 20:41:15 2010
Copyright (c) 1982, 2006, Oracle. All Rights Reserved.
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bit Production
With the Partitioning and Data Mining options
sec@ora10g> insert into t values (2,'ZHS16GBK','AL32UTF8','AL32UTF8','圣');
1 row created.
sec@ora10g> commit;
Commit complete.
5.两种NLS_LANG设置方法下分别查看刚刚插入的两条数据
1)当客户端的NLS_LANG设置为ZHS16GBK时(“转码”场景)。
sec@ora10g> col x for 9
sec@ora10g> col CLIENT_CHARACTERSET for a8
sec@ora10g> col NLS_LANG for a8
sec@ora10g> col DATABASE_CHARACTERSET for a8
sec@ora10g> col y for a4
sec@ora10g> col dump for a50
sec@ora10g> select t.*,dump(y,1016) dump from t order by 1;
X CLIENT_C NLS_LANG DATABASE Y DUMP
-- -------- -------- -------- ---- --------------------------------------------------
1 ZHS16GBK ZHS16GBK AL32UTF8 圣 Typ=1 Len=3 CharacterSet=AL32UTF8: e5,9c,a3
2 ZHS16GBK AL32UTF8 AL32UTF8 ? Typ=1 Len=2 CharacterSet=AL32UTF8: ca,a5
2)当客户端的NLS_LANG设置为AL32UTF8时(“非转码”场景)。
sec@ora10g> col x for 9
sec@ora10g> col CLIENT_CHARACTERSET for a8
sec@ora10g> col NLS_LANG for a8
sec@ora10g> col DATABASE_CHARACTERSET for a8
sec@ora10g> col y for a4
sec@ora10g> col dump for a50
sec@ora10g> select t.*,dump(y,1016) dump from t order by 1;
X CLIENT_C NLS_LANG DATABASE Y DUMP
-- -------- -------- -------- ---- --------------------------------------------------
1 ZHS16GBK ZHS16GBK AL32UTF8 鍦? Typ=1 Len=3 CharacterSet=AL32UTF8: e5,9c,a3
2 ZHS16GBK AL32UTF8 AL32UTF8 圣 Typ=1 Len=2 CharacterSet=AL32UTF8: ca,a5
BTW:有关dump函数的使用方法可以参考Oracle的官方文档
http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions046.htm#SQLRF00635
我这里将return_fmt指定为“1016”,这样会指示出字符集和字符的16进制编码内容。
6.分析与结论
1)“圣”字在ZHS16GBK字符集下的编码是“ca,a5”
这个信息可以从微软的936字符集(ZHS16GBK)中查询得到。
http://www.microsoft.com/globaldev/reference/dbcs/936/936_CA.mspx
2)“圣”字在AL32UTF8字符集下的编码是“e5,9c,a3”
怎么确认“圣”字在UTF8字符集下的编码呢?使用UltraEdit的十六进制编辑模式可以完成这个任务。
将汉字“圣”粘贴到空白的UltraEdit中,依次点选“文件” --> “转换” --> “ASCII转UTF-8(Unicode 编辑)”,然后再一次点选“编辑” --> “十六进制函数” --> “十六进制编辑”(反复切换十六进制编辑模式亦可使用Ctrl+H快捷键来完成),OK,此时便可以得到“圣”字在UTF8字符集下的编码是“E5 9C A3”。
当然,确认“圣”字在ZHS16GBK字符集下的编码也可以使用UltraEdit来完成。
3)结论一
当客户端的NLS_LANG设置为ZHS16GBK时,“圣”字发生了转码,由ZHS16GBK编码“ca,a5”转成了AL32UTF8编码“e5,9c,a3”;
4)结论二
当客户端的NLS_LANG设置为AL32UTF8时,“圣”字没有发生转码,直接以客户端的ZHS16GBK编码“ca,a5”存储在数据库中。
5)“?”的由来
当客户端的NLS_LANG设置为ZHS16GBK时,查询得到的“?”是由UTF-8编码“ca,a5”转换为ZHS16GBK编码后的产物。
6)“鍦?”的由来
这个“鍦”字读作“shi1”(参考:http://www.zdic.net/zd/zi/ZdicE9Zdic8DZdicA6.htm)
因为此时NLS_LANG设置为AL32UTF8,客户端获取数据库信息时将不进行转码,因此在客户端显示的时候将使用“e5,9c,a3”这个编码在936字符集(ZHS16GBK)中寻找匹配的内容。前面的“e5,9c”正好拼接成了“鍦”字,因此“鍦”字便展现在了我们面前。
这个“鍦”字的编码可以在下面的链接中查询到。
http://www.microsoft.com/globaldev/reference/dbcs/936/936_E5.mspx
7.小结
Oracle字符集相关知识涉及面较广,需要静下心来仔细思考其中蕴含的原理。
本文通过实验给大家展示了有关“转码”的相关内容,供参考,希望对大家有帮助。
Good luck.
secooler
10.02.05
-- The End --