Oracle字符集总结归纳

Oracle字符集总结归纳

关键字: oracle
使用常用的 gbk,utf8以及 ascii说明(oracle中对应 hs16gbk,al32utf8,us7ascii)。 
其中,ascii为经典的单字节编码,采用7位,只能表示128个常用字符以及计算机控制字符,不能显示中文等字符;gbk为中国大陆标准,16位,简体中文字符集标准;utf8为unicode的一种最常用实现,兼容ascii的字符使用1位,其余字符都采用3位,可以表示任何字符。Utf8其实已经可以称为国际标准字符集编码,应首先考虑使用utf8。需要说明的是,虽然gbk跟utf8都能表示中文字符,但每个字符的编码是不一样的,所以不能认为是兼容的。 

其实,oracle的字符系统很简单,主要由3部分组成: 
客户终端字符集nls_lang环境变量字符集数据库使用的字符集。其中,客户终端各种各样,比如windows下cmd,unix/linux下terminal/console,甚至如toad等工具也可以视为一个终端。我们使用windows cmd举例说明,cmd使用了gbk编码(好像不能修改) 

nls_lang环境变量决定了终端与服务器连接时,要不要转换字符集,如果nls_lang和服务器端数据库使用的编码不一样,那就要进行转码;如果设为一样,就不会发生转码。 
比如一个终端cmd查询一张数据库表,而其nls_lang设为american_america.zhs16gbk,而数据库为american_america.al32utf8,则数据库中的数据传到终端时,首先要进行utf8到gbk的转码。 

而转码又有两种情况,a.就是一个字符在两中编码里都有,就是具体的码文不一样;b.转码时发现一个字符在另一种编码里没有,则直接用替代字符代替,而这一般就是‘?’字符了。这里要注意的是,我们一般所说的乱码有2种,一种就是b所说的‘?’,而另一种出现的奇奇怪怪的字符就是由于nls_lang设置等转码原因造成的。 
而数据库使用的字符集就是数据库实际使用的字符集。 

现举例说明: 

先创建Oracle数据库utf8使用al32utf8编码,使用cmd(gbk),分以下几种情况: 
a.    设nls_lang也为zhs16gbk,则insert中文时,服务器发现客户端nls_lang为gbk,则要转换映射。输入“我靠”;因为终端为cmd,所以输入的字符集都是gbk编码的,假设“我靠”的gbk编码为0xaabb,则0xaabb要映射为utf8(假设“我靠”的utf8编码为0xccddee)编码,存入数据库,则数据中保存了utf8编码的“我靠“。然后,再使用cmd进行select查询,数据库发现nls_lang为zhs16gbk,则把”我靠“从utf8码0xccddee转为gbk的0xaabb,然后正常在cmd中显示”我靠“两字。 
     
b.    设nls_lang也为al32utf8,则从cmd输入“我靠“时,服务器发现客服端nls_lang为utf8,则它不进行转换,直接存0xaabb进数据库;当select时,因为也不要转换,所以直接发0xaabb给终端,而0xaabb在终端cmd(gbk)里显示为“我靠”,也能正常显示。但要注意的是,这时对服务器来说,存在数据库里的内容其实是不正确的,不是正确的“我靠”的utf8编码;而只是存了个“我靠“的gbk编码。 
c.    先设nls_lang为utf8,输入完“我靠“后,改nls_lang为gbk,再做select,发现显示为乱码了。这种就是前面说的因为转码问题造成的乱码。因为数据库一开始存的是”我靠“的gbk码0xaabb;然后做select时,因为使用了改为gbk的nls_lang,则数据库要进行转码了,就是要把utf8中的0xaabb转为gbk码,假设utf8中0xaabb表示的是”B??“,那就是要把”B??“转为gbk码,然后在cmd中用gbk显示了”B??“乱码。
     
     

然后,我们再次创建一个us7ascii码的数据库chr。 
d. 设nls_lang为american_america.us7ascii,输入“我靠“,然后再select,发现竟然能正常显示中文。这是因为由于数据库编码和nls_lang编码一样,所以不进行转码,直接把”我靠“的gbk码0xaabb输入了数据库。而select时,由于也不要转码,所以又直接把0xaabb传了回来,在cmd(gbk)中就显示了”我靠“。 
    
e. 延续d的情况,再设nls_lang为american_america.zhs16gbk,再做select,发现返回NR??,这种情况还是前面所说的转码造成的乱码,因为gbk是兼容ascii的,只是这里还是进行了错误的转码,因为ascii中的0xaabb转码成gbk显示,就是NR??。 
f. 设nls_lang为american_america.zhs16gbk,输入“我靠“,然后再select,发现返回两个??;这是因为”我靠“的gbk编码要转码到uscii时,因为uscii里没有”我靠“两个字符的编码,所以不兼容,直接用两个?代替;而select时,因为ascii里的?和gbk里的?是兼容的,所以转码后,cmd里也显示两个?。 
     

综上所述,可以得出如下规范: 
1.        数据库字符应该至少使用gbk,最好是utf8字符集,这样至少基本上不会出现全问号乱码的情况,因为不会出现找不到对应字符,而采用?等字符代替的情况。情况f其实就是这样。 
2.        应该设置nls_lang和终端使用一样的编码,这样数据库也能正确知道终端使用的编码,就能正确得转码,就不大会把错误的编码存进数据库,情况b,c,d,e就是设错了nls_lang才造成了问题。这里面,还有种情况,就是不设nls_lang时,好像oracle默认会把它当作和终端编码一样(需要确认)。 
3.        尽量使得3个编码都一样,这样就能避免编码转换造成的性能损失。 


其实,不仅oracle,别的一些数据库,甚至是一些编程工具,如jsp/servlet等都有类似的编码体制,基本上都是终端(如jsp里为编辑器),环境变量(jsp里为pageencoding指令),服务器端编码(jsp为浏览器等);再比如oracle做imp时,终端编码就为dmp包中的编码(不一定为原数据库编码,因为有可能它在exp时,已经转过码了),环境变量编码还是nls_lang,而服务端就是要实行imp的数据库的编码了。 
有兴趣的话,大家可以研究下mysql的字符集机制,它本质上还是使用三位一体的编码机制,但划分的更细。 

From: http://tanrenjie.spaces.live.com/blog/cns!599006622366184E!343.entry 

你可能感兴趣的:(oracle,职场,字符集,休闲)