【字符集】论Oracle字符集“转码”过程

本文将通过实验来演示一下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
【字符集】论Oracle字符集“转码”过程_第1张图片

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
【字符集】论Oracle字符集“转码”过程_第2张图片

7.小结
Oracle字符集相关知识涉及面较广,需要静下心来仔细思考其中蕴含的原理。
本文通过实验给大家展示了有关“转码”的相关内容,供参考,希望对大家有帮助。

Good luck.

secooler
10.02.05

-- The End --

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/519536/viewspace-626952/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/519536/viewspace-626952/

你可能感兴趣的:(【字符集】论Oracle字符集“转码”过程)