提及Oracle字符集可以说是老生常,Oracle字符集问题的引起,主要是因为其的“乱码”问题。而乱码的产生主要是因为客户端和服务器的实际应用的字符集不同,其进行字符集转换而引起的。
不过很多提到了转换,却没有提到这个转换是在哪个阶段和哪里发生的?是在服务器向块里写入数据的时候吗?在客户端还是在服务器端?
正确的答案是,普通字符串转换发生在客户端(具体来说是由OCI LIBRARY完成的),国家字符串经过两次转换,***次发生在客户端,第二次发生在服务器端。下面做个测试:
连接到:
- Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
- With the Partitioning, Real Application Clusters, OLAP and Data Mining options
- SQL> select * from nls_database_parameters where parameter like ‘%CHARACTERSET%’;
- PARAMETER VALUE
- ------------------------------ ------------------------------
- NLS_CHARACTERSET ZHS16GBK
- NLS_NCHAR_CHARACTERSET AL16UTF16
- SQL> create table t1(a varchar2(100));
表已创建。
- SQL>
- SQL> insert into t1 values (’中’);
已创建 1 行。
- SQL>
在本次连接中,我没有设置NLS_LANG变量。则客户端Oracle字符集为操作系统的缺省字符集ZHS16GBK。通过捕获网络包,可以发现客户端传送给客户端的数据(不能上传图片,郁闷):
- 00000090 00 00 00 00 00 00 00 00 00 00 00 28 DB 00 01 1C ………..(….
- 000000A0 69 6E 73 65 72 74 20 69 6E 74 6F 20 74 31 20 76 insert.into.t1.v
- 000000B0 61 6C 75 65 73 20 28 27D6 D027 29 01 00 00 00 alues.(’..’)….
- 000000C0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …………….
注意红色的部分,16进制D6 D0正是“中”字的GBK编码。(关于怎么获取汉字的各种编码,暂且略过,如有需要再交流)
现在我们退出SQLPLUS,设置环境变量NLS_LANG:
- SQL> rollback;
回退已完成。
- SQL> exit
- Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
- With the Partitioning, Real Application Clusters, OLAP and Data Mining options
断开
- C:\Documents and Settings\Administrator>set nls_lang=american_america.us7ascii
- C:\Documents and Settings\Administrator>sqlplus test/test@dmdb
- SQL*Plus: Release 10.2.0.1.0 - Production on Mon Jan 28 00:48:41 2008
- Copyright (c) 1982, 2005, Oracle. All rights reserved.
- Connected to:
- Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
- With the Partitioning, Real Application Clusters, OLAP and Data Mining options
- SQL> insert into t1 values (’中’);
- 1 row created.
抓获的网络包发现,在SQL提交给服务器之前已经转换了。OCI库认为提交过来的编码是US7ASCII,因此要将转换为服务器端的ZHS16GBK编码,然而“中”的编码即16进制D6 D0并不是有效的US7ASCII编码,所以ORACLE OCI就转为了转省值3F3F(US7ASCII是单字节Oracle字符集,会认为“中”字是两个字符,因此为有两个3F) 这就是“??”号的由来。
- 00000090 00 00 00 00 00 00 00 00 00 00 00 C8 1D FF 00 1C …………….
- 000000A0 69 6E 73 65 72 74 20 69 6E 74 6F 20 74 31 20 76 insert.into.t1.v
- 000000B0 61 6C 75 65 73 20 28 273F 3F27 29 01 00 00 00 alues.(’??’)….
- 000000C0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …………….
我们再看看将客户端NLS_LANG设置为simplified chinese_china.zhs16cgb231280会发生什么以上的相关内容就是对再论Oracle字符集转换的部分内容的介绍。
【编辑推荐】
- Oracle SMON进程的说明经典版
- Oracle存储过程的编写经验总结
- Oracle EXPLAIN PLAN实际应用技巧心得
- Oracle数据库设计规范化的前两个要求
- Oracle树的存储过程的实际操作4步骤