彻底搞懂Oracle字符集
基本概念 SQL> select * from v$nls_parameters where parameter='NLS_CHARACTERSET'; PARAMETER VALUE ------------------------------ ----------------- NLS_CHARACTERSET AL32UTF8 2. 客户端操作系统字符集:即客户端操作系统以哪种字符编码存储字符。 如果是Windows,可以使用chcp命令获得代码页(code page): 复制代码 代码如下: C:Usersxianzhu>chcp Active code page: 936 根据该代码页,到微软的官方文档《 National Language Support (NLS) API Reference 》找到其对应的字符集。 如果是Linux,字符集在/etc/sysconfig/i18n设置: 复制代码 代码如下: LANG="zh_CN.GB2312" (指定当前操作系统的字符集) SUPPORTED="zh_CN.GB2312"(指定当前操作系统支持的字符集) SYSFONT="lat0-sun16"(指定当前操作系统的字体) 3. 客户端NLS_LANG参数:该参数用于向Oracle指示客户端操作系统的字符集。 有了以上3个基本概念之后,我来阐述一下Oracle字符集转换的基本原则: 1.设置客户端的NLS_LANG为客户端操作系统的字符集 2.如果数据库字符集等于NLS_LANG,数据库和客户端传输字符时不作任何转换 3.如果它们俩不等,则需要在不同字符集间转换,只有客户端操作系统字符集是数据库字符集子集的基础上才能正确转换,否则会出现乱码。
数据库与客户端之间字符集设置关系如下:
数据库...............................................................................AL32UTF8 NLS_LANG客户端设置..................SESSION1:AL32UTF8 SESSION2:ZHS16GBK ================================================================================= 客户端...............................................................................ZHS16GBK
如果数据库与客户端字符集不一致,一定要用SESSION2的设置方法来设置数据的NLS_LANG值
下面先看一个例子,再透过现象看本质,我们会针对这个例子进行分析。 该例子如下: 复制代码 代码如下: 1. 数据库字符集为Unicode(UTF-8编码) 我们的数据库版本是10.2.0.4.0,数据库字符集是: SQL> select * from v$nls_parameters where parameter='NLS_CHARACTERSET'; PARAMETER VALUE ---------------------------------------- ------------------------------ NLS_CHARACTERSET AL32UTF8 2. 客户端操作系统字符集为代码页936(字符集为ZHS16GBK) 可以使用chcp获得windows的代码页(code page) C:Documents and Settingsa105024Desktop>chcp Active code page: 936 3. 创建测试表 SQL> create table test(id number,var varchar2(30)); Table created. 4. 插入数据 这里在同一个操作系统启动两个session,session1的NLS_LANG设为和数据库字符集一样(即AL32UTF8): C:Documents and Settingsa105024Desktop>set nls_lang=Simplified Chinese_China.AL32UTF8 连接数据库并插入一条数据: Session_1>insert into test values(1,'中国'); 1 row created. Session_1>commit; Commit complete. session2的NLS_LANG设为和客户端操作系统一样(即ZHS16GBK): C:Documents and Settingsa105024Desktop>set nls_lang=Simplified Chinese_China.ZHS16GBK 连接数据库并插入一条数据: Session_2>insert into test values(2,'中国'); 1 row created. Session_2>commit; Commit complete. 5. 执行查询 在session 1上执行查询: Session_1>select * from test; ID VAR ---------- --------------------- 1 中国 2 涓 浗 在session 2上执行查询: Session_2>select * from test; ID VAR ---------- -------------------- 1 ??? 2 中国 上面例子看起来很诡异,session1和2都能正常显示自己插入的字符串,又都不能正常显示对方插入的字符串。为了弄清楚,我们首先得知道数据库里对这两个字符串是怎么存储的。我们可以使用dump函数获得字符在数据库的编码: 复制代码 代码如下: SQL> select id,dump(var,1016) from test; ID DUMP(VAR,1016) -- ------------------------------------------------------------ 1 Typ=1 Len=4 CharacterSet=AL32UTF8: d6,d0,b9,fa 2 Typ=1 Len=6 CharacterSet=AL32UTF8: e4,b8,ad,e5,9b,bd 根据AL32UTF8的编码,“中国”两字的正确编码为(都为3个字节): 中--e4,ad 国--e5,bd 因此session 1插入的字符串在数据库中的编码是错误的,session 2正确。这也是为什么一定要设置NLS_LANG为客户端操作系统的字符集。 但是根据上面实验我们可以知道,数据库中存储正确,并不代表客户端能正常显示;同样地,即时数据库没有正确存储,有时候客户端也能够正常显示,这又是为什么呢?别急,请听我慢慢道来: 场景1:session 1插入,session 1查询,在数据库中存储错误,但显示正确。 Session_1>select length(var) from test where id=1; LENGTH(VAR) ----------- 3 得出的长度居然为3!实际的长度只是2,这会带来很多麻烦。 场景2:session 1插入,session 2查询,在数据库中存储错误,显示也错误。 场景3:session 2插入,session 1查询,在数据库中存储正确,但显示错误。 场景4:session 2插入,session 2查询,在数据库中存储正确,显示也正确。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |