在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
基本概念 复制代码 代码如下: SQL> select * from v$nls_parameters where parameter='NLS_CHARACTERSET'; PARAMETER VALUE ------------------------------ ----------------- NLS_CHARACTERSET AL32UTF8 2. 客户端操作系统字符集:即客户端操作系统以哪种字符编码存储字符。 如果是Windows,可以使用chcp命令获得代码页(code page): 复制代码 代码如下: C:\Users\xianzhu>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.如果它们俩不等,则需要在不同字符集间转换,只有客户端操作系统字符集是数据库字符集子集的基础上才能正确转换,否则会出现乱码。 几种常见情况分析 下面先看一个例子,再透过现象看本质,我们会针对这个例子进行分析。 该例子如下: 复制代码 代码如下: 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 Settings\a105024\Desktop>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 Settings\a105024\Desktop>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 Settings\a105024\Desktop>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,b8,ad 国--e5,9b,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查询,在数据库中存储正确,显示也正确。 |
请发表评论