当前位置:  数据库>oracle

[Oracle] 彻底搞懂Oracle字符集

    来源: 互联网  发布时间:2014-10-04

    本文导语:  基本概念字符集(Character set):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。常见的字符集有ASCII,ZHS16GB231280,ZHS16GBK等。字符编码(Character Encoding...

基本概念
字符集(Character set):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。常见的字符集有ASCII,ZHS16GB231280,ZHS16GBK等。

字符编码(Character Encoding):是一套法则,使用该法则能够对自然语言的字符的一个集合(如字母表或音节表),与其它的一个集合(如电脑编码)进行配对。即在符号集合与数字系统之间建立对应关系。与字符集相对应,常见的字符编码有:ASCii,ZHS16GBK,ZHT16BIG5,ZHS32GB18030等。
字符集的定义其实就是字符的集合,而字符编码则是指怎么将这些字符变成字节用于保存、读取和传输。

万国码(Unicode):包含了几乎人类所有可用的字符,每年还在不断的增加,可以看作是一种通用的字符集。它将全世界所有的字符统一化,统一编码,不会再出现字符不兼容和字符转换的问题。
它有以下三种编码方式:
1.UTF-32编码:固定使用4个字节来表示一个字符,存在空间利用效率的问题。
2.utf-8编码:对相对常用的60000余个字符使用两个字节进行编码,其余的使用4字节。
3.UTF- 8编码:兼容ASCII编码;拉丁文、希腊文等使用两个字节;包括汉字在内的其它常用字符使用三个字节;剩下的极少使用的字符使用四个字节。

Oracle字符集基本原理
在搞懂Oracle字符集基本原理之前,一定要先分清以下三个概念:
1. Oracle数据库服务器字符集:即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.如果它们俩不等,则需要在不同字符集间转换,只有客户端操作系统字符集是数据库字符集子集的基础上才能正确转换,否则会出现乱码。
几种常见情况分析
下面先看一个例子,再透过现象看本质,我们会针对这个例子进行分析。
该例子如下:
代码如下:

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,b8,ad
国--e5,9b,bd
因此session 1插入的字符串在数据库中的编码是错误的,session 2正确。这也是为什么一定要设置NLS_LANG为客户端操作系统的字符集。
但是根据上面实验我们可以知道,数据库中存储正确,并不代表客户端能正常显示;同样地,即时数据库没有正确存储,有时候客户端也能够正常显示,这又是为什么呢?别急,请听我慢慢道来:

场景1:session 1插入,session 1查询,在数据库中存储错误,但显示正确。
插入过程:
”中国“两字在客户端操作系统字符集ZHS16GBK中的编码是”d6,d0,b9,fa",由于NLS_LANG和数据库字符集相同,数据库端对客户端传过来的字符编码不进行任何转换直接存入数据库,因此数据库中存储的编码也是“d6,d0,b9,fa”,
读取过程:
数据库端读取的编码是“d6,d0,b9,fa”,由于NLS_LANG和数据库字符集相同,客户端对数据库端传过来的字符编码不进行任何转换直接显示,编码”d6,d0,b9,fa“在客户端操作系统字符集ZHS16GBK对应的汉字为“中国”。

从以上分析可知,虽然读取时正确的,但那是因为负负得正,实际上数据库中存储是错误的,因此要特别小心这种情况,在生成库中要避免。其实只要对它进行length操作就能轻易揭开它的假面具:

代码如下:

Session_1>select length(var) from test where id=1;
LENGTH(VAR)
-----------
          3

得出的长度居然为3!实际的长度只是2,这会带来很多麻烦。

场景2:session 1插入,session 2查询,在数据库中存储错误,显示也错误。
插入过程和场景1一样,这里就不再累述。
读取过程:
数据库端读取的编码是“d6,d0,b9,fa”,由于NLS_LANG和数据库字符集不同,客户端对数据库端传过来的字符编码进行转换,数据库端字符集AL32UTF8里编为“d6,d0,b9,fa”无法在客户端操作系统字符集ZHS16GBK里找到对应的编码,所以只好用?代替。

场景3:session 2插入,session 1查询,在数据库中存储正确,但显示错误。
插入过程:
”中国“两字在客户端操作系统字符集ZHS16GBK中的编码是”d6,d0,b9,fa",由于NLS_LANG和数据库字符集不同,Oracle会进行字符编码转换,也就是将字符集ZHS16GBK里“中国”的编码“d6,d0,b9,fa"转换为字符集"AL32UTF8"里”中国“的编码”e4,b8,ad,e5,9b,bd“。
读取过程:
数据库端读取的编码是”e4,b8,ad,e5,9b,bd“,由于NLS_LANG和数据库字符集相同,客户端对数据库端传过来的字符编码不进行任何转换直接显示,编码”e4,b8,ad,e5,9b,bd“在客户端操作系统字符集ZHS16GBK对应的汉字为“涓   浗”(原本2个字符,现在变成了3个字符,因为ZHS16GBK的汉字以2个字节编码)。

场景4:session 2插入,session 2查询,在数据库中存储正确,显示也正确。
插入过程和场景3类似。
读取过程:
数据库端读取的编码是”e4,b8,ad,e5,9b,bd“,由于NLS_LANG和数据库字符集不同,客户端对数据库端传过来的字符编码进行转换,数据库端字符集AL32UTF8里”中国“两字的编码”e4,b8,ad,e5,9b,bd“转换成客户端操作系统字符集ZHS16GBK里“中国”两字的编码“d6,d0,b9,fa",并正常显示。
这种情况虽然经过了两次转换,都确实最正确、最推荐的方式。

附录:Oracle 字符集超集和子集的对应关系可查看:http://download.oracle.com/docs/cd/B19306_01/server.102/b14225/applocaledata.htm#sthref1988

结论:NLS_LANG只和客户端操作系统的字符集相关,如果客户端操作系统的字符集和数据库字符集间无法正确转换,则应该首先改变客户端终端的字符集,而不是简单地把NLS_LANG设为和数据库字符集一样。


    
 
 

您可能感兴趣的文章:

  • 在Red Hat Linux 9 和 Oracle 9.2 环境下,如何配制字符集,让Oracle能存入并显示日语里的假名?
  • 查询与修改Oracle字符集
  • oracle查看字符集后修改oracle服务端和客户端字符集的步骤
  • ORACLE 10G修改字符编码没有超字符集的限制
  • apache通过php的oci函数读取Oracle(字符集ZHS16GBK)时,显示乱码,如何解决?
  • 查看和修改Oracle服务器端字符集
  • Oracle字符集修改查看方法
  • 如何在RAC环境下修改Oracle字符集
  • oracle查询字符集语句分享
  • Oracle 8i字符集乱码问题析及其解决办法
  • 最好的修改Oracle字符集文档
  • Oracle中字符集的类型决定varchar2的字符长度
  • oracle查看字符集和修改字符集使用详解
  • 深入Oracle字符集的查看与修改详解
  • oracle截取字符(substr)检索字符位置(instr)示例介绍
  • 关于Oracle BLOB类型,一个String字符怎么写入BLOB字段?
  • Oracle中SQL语句连接字符串的符号使用介绍
  • Oracle中字符串连接的实现方法
  • Oracle将字符编码从GBK转到UTF8,如何操作比较稳妥?
  • 安装oracle9的时候字符无法显示??
  • oracle查询不含括号及不含指定字符的方法
  • 网络技术 iis7站长之家
  • 怎么用jsp向oracle8提交长字符(15000字左右)?
  • 向Oracle数据库的CLOB属性插入数据报字符串过长错误
  • 快疯了:怎样从JSP中向Oracle_816中插入LONG型字符串?
  • Linux下字符安装oracle好轻松
  • oracle使用instr或like方法判断是否包含字符串
  • Oracle用户密码含特殊字符时登陆失败问题
  • linux下字符安装oracle 10g!最后出现点问题!很急!
  • 我要向oracle中插入大文本,用的是lang类型的字段,但是只能插3000字,再多就抱错,说我字符串过长。谁遇到过此问题?
  • Oracle中如何插入特殊字符:& 和 '(多种解决方案)
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • Oracle 12c发布简单介绍及官方下载地址
  • 在linux下安装oracle,如何设置让oracle自动启动!也就是让oracle那个服务自动启动,不是手动的
  • oracle 11g最新版官方下载地址
  • 请问su oracle 和su - oracle有什么不同?
  • Oracle 数据库(oracle Database)Select 多表关联查询方式
  • 虚拟机装Oracle R12与Oracle10g
  • Oracle数据库(Oracle Database)体系结构及基本组成介绍
  • Oracle 数据库开发工具 Oracle SQL Developer
  • 如何设置让Oracle SQL Developer显示的时间包含时分秒
  • Oracle EBS R12 支持 Oracle Database 11g
  • Oracle 10g和Oracle 11g网格技术介绍
  • SCO unix下安装oracle,但没有光盘,请大家推荐一个oracle下载站点(unix版本的)。谢谢!!!!
  • oracle中如何把表中具有相同值列的多行数据合并成一行
  • 请问大家用oracle数据库, 用import oracle.*;下的东西么? 还是用标准库?
  • Oracle 数据库(oracle Database)性能调优技术详解
  • Linux /$ORACLE_HOME $ORACLE_HOME
  • ORACLE日期相关操作
  • Linux系统下Oracle的启动与Oracle监听的启动
  • ORACLE数据库常用字段数据类型介绍
  • 请问在solaris下安装ORACLE,用root用户和用oracle用户安装有什么区别么?
  • Oracle 12c的九大最新技术特性介绍
  • 网间Oracle的连接,远程连接Oracle服务器??


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3