ITPub博客

首页 > 数据库 > Oracle > 字符集的理解与乱码的解决 必须操作系统字符集

字符集的理解与乱码的解决 必须操作系统字符集

原创 Oracle 作者:li__hl8888 时间:2016-06-02 14:13:17 0 删除 编辑


1>这种情况下不会产生乱码。

操作系统字符集 <=NLS_LANG (客户端字符集 ) <=数据库字符集 charactor set example:ZHS16GBK,AL32UTF8


1〉数据库字符集 charactor set example:ZHS16GBK,AL32UTF8

2〉客户端字符集 注册表 NLS_LANG ,LINUX下表现为profile

3〉操作系统字符集 控制面板 或c:>chcp  返回代码936 对应zhs16gbk

当这三个字符集能自由正确转换,都能找到对应关系,将不再产生乱码。

注意应用程序所采用的NLS_LANG以及所使用的ORACLE_HOME


2>产生乱码的解决方式:

1〉认定是否是真正的乱码。显示是乱码不代表数据库存储了不正确的数据。

2〉


1>Language 消息。 Territory:货币,数字,地区和计算星期和日期

速记:按照日期,星期(两期)计算地区数字货币。


注意事项:


1>当客户端字符集与数据库字符集一样,操作系统字符集和数据库字符集不一样时,一旦操作系统输入字符在数据库中找不到

相应映射的字符代码 ,这个时候乱码产生了。。。


2>

数据的存储实际上要经过至少两次转化才能保存在数据库中,但是当NLS_LANG和数据库一致时,只需要从操作系统字符集转化为数据库字符集。


3〉理解超集和子集。v$nls_valid_values.


很多朋友经常问起Oracle字符集子集与超级的对应关系,我将从Oracle8.1.6到9.2.0的对应关系列举在这里供大家参考.参考文档Metalink Doc: 119164.1

尤其是在更改字符集时,大家应该参考此对应关系:

8.1.6 Subset/Superset Pairs

===========================

A. Current Char set             B. New Char set (Superset of A.)

-------------------             --------------------------------

US7ASCII                        WE8DEC

US7ASCII                        US8PC437

US7ASCII                        WE8PC850

US7ASCII                        IN8ISCII

US7ASCII                        WE8PC858

US7ASCII                        WE8ISO8859P1

US7ASCII                        EE8ISO8859P2

US7ASCII                        SE8ISO8859P3

US7ASCII                        NEE8ISO8859P4

US7ASCII                        CL8ISO8859P5

US7ASCII                        AR8ISO8859P6

US7ASCII                        EL8ISO8859P7

US7ASCII                        IW8ISO8859P8

US7ASCII                        WE8ISO8859P9

US7ASCII                        NE8ISO8859P10

US7ASCII                        TH8TISASCII

US7ASCII                        BN8BSCII

US7ASCII                        VN8VN3

US7ASCII                        VN8MSWIN1258

US7ASCII                        WE8ISO8859P15

US7ASCII                        WE8NEXTSTEP

US7ASCII                        AR8ASMO708PLUS

US7ASCII                        EL8DEC

US7ASCII                        TR8DEC

US7ASCII                        LA8PASSPORT

US7ASCII                        BG8PC437S

US7ASCII                        EE8PC852

US7ASCII                        RU8PC866

US7ASCII                        RU8BESTA

US7ASCII                        IW8PC1507

US7ASCII                        RU8PC855

US7ASCII                        TR8PC857

US7ASCII                        CL8MACCYRILLICS

US7ASCII                        WE8PC860

US7ASCII                        IS8PC861

US7ASCII                        EE8MACCES

US7ASCII                        EE8MACCROATIANS

US7ASCII                        TR8MACTURKISHS

US7ASCII                        EL8MACGREEKS

US7ASCII                        IW8MACHEBREWS

US7ASCII                        EE8MSWIN1250

US7ASCII                        CL8MSWIN1251

US7ASCII                        ET8MSWIN923

US7ASCII                        BG8MSWIN

US7ASCII                        EL8MSWIN1253

US7ASCII                        IW8MSWIN1255

US7ASCII                        LT8MSWIN921

US7ASCII                        TR8MSWIN1254

US7ASCII                        WE8MSWIN1252

US7ASCII                        BLT8MSWIN1257

US7ASCII                        N8PC865

US7ASCII                        BLT8CP921

US7ASCII                        LV8PC1117

US7ASCII                        LV8PC8LR

US7ASCII                        LV8RST104090

US7ASCII                        CL8KOI8R

US7ASCII                        BLT8PC775

US7ASCII                        WE8DG

US7ASCII                        WE8NCR4970

US7ASCII                        WE8ROMAN8

US7ASCII                        WE8MACROMAN8S

US7ASCII                        TH8MACTHAIS

US7ASCII                        HU8CWI2

US7ASCII                        EL8PC437S

US7ASCII                        LT8PC772

US7ASCII                        LT8PC774

US7ASCII                        EL8PC869

US7ASCII                        EL8PC851

US7ASCII                        CDN8PC863

US7ASCII                        HU8ABMOD

US7ASCII                        AR8ASMO8X

US7ASCII                        AR8NAFITHA711T

US7ASCII                        AR8SAKHR707T

US7ASCII                        AR8MUSSAD768T

US7ASCII                        AR8ADOS710T

US7ASCII                        AR8ADOS720T

US7ASCII                        AR8APTEC715T

US7ASCII                        AR8NAFITHA721T

US7ASCII                        AR8HPARABIC8T

US7ASCII                        AR8NAFITHA711

US7ASCII                        AR8SAKHR707

US7ASCII                        AR8MUSSAD768

US7ASCII                        AR8ADOS710

US7ASCII                        AR8ADOS720

US7ASCII                        AR8APTEC715

US7ASCII                        AR8MSAWIN

US7ASCII                        AR8NAFITHA721

US7ASCII                        AR8SAKHR706

US7ASCII                        AR8ARABICMACS

US7ASCII                        LA8ISO6937

US7ASCII                        JA16VMS

US7ASCII                        JA16EUC

US7ASCII                        JA16SJIS

US7ASCII                        KO16KSC5601

US7ASCII                        KO16KSCCS

US7ASCII                        KO16MSWIN949

US7ASCII                        ZHS16CGB231280

US7ASCII                        ZHS16GBK

US7ASCII                        ZHT32EUC

US7ASCII                        ZHT32SOPS

US7ASCII                        ZHT16DBT

US7ASCII                        ZHT32TRIS

US7ASCII                        ZHT16BIG5

US7ASCII                        ZHT16CCDC

US7ASCII                        ZHT16MSWIN950

US7ASCII                        AL24UTFFSS

US7ASCII                        UTF8

US7ASCII                        JA16TSTSET2

US7ASCII                        JA16TSTSET

8.1.7 Additions

===============

US7ASCII                        ZHT16HKSCS 

US7ASCII                        KO16TSTSET 

WE8DEC                          TR8DEC 

WE8DEC                          WE8NCR4970 

WE8PC850                        WE8PC858 

D7DEC                           D7SIEMENS9780X 

I7DEC                           I7SIEMENS9780X 

WE8ISO8859P1                    WE8MSWIN1252 

AR8ISO8859P6                    AR8ASMO708PLUS 

AR8ISO8859P6                    AR8ASMO8X 

IW8EBCDIC424                    IW8EBCDIC1086 

IW8EBCDIC1086                   IW8EBCDIC424 

LV8PC8LR                        LV8RST104090 

DK7SIEMENS9780X                 N7SIEMENS9780X 

N7SIEMENS9780X                  DK7SIEMENS9780X 

I7SIEMENS9780X                  I7DEC 

D7SIEMENS9780X                  D7DEC 

WE8NCR4970                      WE8DEC 

WE8NCR4970                      TR8DEC 

AR8SAKHR707T                    AR8SAKHR707 

AR8MUSSAD768T                   AR8MUSSAD768 

AR8ADOS720T                     AR8ADOS720 

AR8NAFITHA711                   AR8NAFITHA711T 

AR8SAKHR707                     AR8SAKHR707T 

AR8MUSSAD768                    AR8MUSSAD768T 

AR8ADOS710                      AR8ADOS710T 

AR8ADOS720                      AR8ADOS720T 

AR8APTEC715                     AR8APTEC715T 

AR8NAFITHA721                   AR8NAFITHA721T 

AR8ARABICMAC                    AR8ARABICMACT 

AR8ARABICMACT                   AR8ARABICMAC 

KO16KSC5601                     KO16MSWIN949 

WE16DECTST2                     WE16DECTST 

WE16DECTST                      WE16DECTST2 

  

9.0.1 Additions

===============

US7ASCII                        BLT8ISO8859P13 

US7ASCII                        CEL8ISO8859P14 

US7ASCII                        CL8ISOIR111 

US7ASCII                        CL8KOI8U 

US7ASCII                        AL32UTF8 

BLT8CP921                       BLT8ISO8859P13 

US7ASCII                        AR8MSWIN1256 

UTF8                            AL32UTF8 (added in patchset 9.0.1.2)

Character Set Subset/Superset Pairs Obsolete from 9.0.1

=======================================================

US7ASCII                        AR8MSAWIN

AR8ARABICMAC                    AR8ARABICMACT

9.2.0 Additions

===============

US7ASCII                        JA16EUCTILDE

US7ASCII                        JA16SJISTILDE

US7ASCII                        ZHS32GB18030

US7ASCII                        ZHT32EUCTST

WE8ISO8859P9                    TR8MSWIN1254

LT8MSWIN921                     BLT8ISO8859P13

LT8MSWIN921                     BLT8CP921

BLT8CP921                       LT8MSWIN921

AR8ARABICMAC                    AR8ARABICMACT

ZHT32EUC                        ZHT32EUCTST

UTF8                            AL32UTF8

Character Set Subset/Superset Pairs Obsolete from 9.2.0

=======================================================

LV8PC8LR                        LV8RST104090


网络上的这篇文章写的法不错,关于乱码的,如下:

原文如下:




作为一个ORACLEDBA,在工作中会经常处理由于字符集产生的一些问题。但是当真正


想写一些这方面的东西时,却突然又没有了头绪。发了半天呆,还是决定用两个字符集方面


的例子作为切入点,倒不失为一个头绪,说不定在实验的过程中,问题就会一个接着一个的


浮现出来。


现在,让我们切入正题。


我用的数据库是oracle10.2.0.3,数据库字符集是al32utf8。


客户端就是同一台机器的windowsxp.


下面是演示的例子:


SQL>droptable testpurge;


Tabledropped.


SQL>createtable test(col1number(1),col2varchar2(10));


Tablecreated.


--session 1 设置客户端字符集为zhs16gbk(修改注册表nls_lang项的characterset 为


zhs16gbk)向表中插入两个中文字符。


SQL>insert intotest values(1,'中国'); --1为session1的标记


1rowcreated.


SQL>commit;


Commitcomplete.


--session2设置客户端字符集al32utf8(修改注册表nls_lang项的characterset 为al32utf8),


与数据库字符集相同。向表中插入两个和session1相同的中文字符。


SQL>insert intotest values(2,'中国'); --2为session2的标记


1rowcreated.


SQL>commit;


Commitcomplete.


--session1


SQL>select*fromtest;


COL1COL2


------------------------------2???


1中国


--session2


SQL>select*fromtest;


COL1COL2


--------------------2中国


1涓?浗


从session1和session2的结果中可以看到,相同的字符(注意,我指的是我们看到的,


显示为相同的字符),在不同的字符集输入环境下,显示成了乱码。


在zhs16gbk字符集的客户端,我们看到了utf8字符集客户端输入的相同的中文变成了乱


码-->col1=2 的col2字段


在utf8字符集客户端,我们看到zhs16gbk字符集的客户端输入的中文变成了另外的字符


-->col1=1 的col2字段


从这个例子里,我们好像感觉到出了什么问题,也可能会联想起现实环境中出现的乱码问题。


问题似乎有了思路,ok,让我们继续把实验做下去:


--session1(或者session2,在这里无所谓)


SQL>selectcol1,dump(col2,1016)fromtest;


COL1


----------DUMP(COL2,1016)


--------------------------------------------------------------------------------2


Typ=1Len=4CharacterSet=AL32UTF8:d6,d0,b9,fa


1


Typ=1Len=6CharacterSet=AL32UTF8:e4,b8,ad,e5,9b,bd


我们使用了dump函数,结果看起来很明显了,两个完全相同的字符,在不同的字符集


环境下,在数据库中存储成了不同的编码。


对于ZHS16GBK的字符集客户端输入的字符"中国",AL32UTF8使用了3个字节来分别


存储一个字符,即:


中--e4,b8,ad


国--e5,9b,bd


我们也可以分别对这个字符进行验证:


--session1


SQL>selectdump('中',1016) fromdual;


DUMP('中',16)


--------------------------------------------Typ=96Len=3CharacterSet=AL32UTF8:e4,b8,ad--字符“中”,和上面直接从数据库中读取存储的


字符编码一致。


SQL>selectdump('国',1016) fromdual;


DUMP('国',16)


--------------------------------------------Typ=96Len=3CharacterSet=AL32UTF8:e5,9b,bd--字符“国”,和上面直接从数据库中读取存储的


字符编码一致。


如果使用session2直接对着两个字符进行测试,一样会得到相同的结果(笔者已经做


过测试,这里为了避免冗长,删掉了).


让我们重新来理一下思路,并提出几个问题:


1:为什么显示为相同的字符,存储到数据库中却变成了不同的编码?


2:我们在向数据库中插入数据的时候,oracle究竟做了些什么?


3:操作系统字符集,客户端字符集,数据库字符集究竟是什么关系?


带着这些疑惑,让我们接着做实验,所有的疑团和猜测都会在试验中得以验证。


我的思路是,先取得测试环境的相关参数。


1:windows字符集(codepage)


我们使用chcp命令来获得windows使用的字符集


c:\chcp


活动的代码页: 936


通过oracle的官方文档阅读,我们可以将它等同于ZHS16GBK字符集(在安装oracle


时,oracle会找到安装平台的字符集,并默认将对应的字符集设置成与它相同,在这里,数


据库默认的字符集本身应该是ZHS16GBK,但我强制将它修改为AL32UTF8)。


所以现在我们可以认为,我们使用的操作系统是ZHS16GBk字符集,那么我们在这个


环境下输入的字符(也可以说是显示的字符,用的就是这个字符集的编码)。


让我们继续讨论问题。


我们现在要讨论一下客户端字符集究竟是用来做什么的。


我们知道,很多字符集都有自己的编码方式,换句话说,相同的字符,在不同的字符集


里对应的编码可能是不一样的。


客户端的字符集就是为了让数据库知道我们传递过去的字符是属于那种字符集,以便于


oracle在存储字符时做相应的编码映射。


拿上面的例子来说:


比如字符"中国"


在ZHS16GBK字符集中,它的编码是:d6,d0,b9,fa


在AL32UTF8字符集中,它的编码是:e4,b8,ad,e5,9b,bd


让我们看看例子中两个session输入的相同字符在数据库中存储对应的编码:


SQL>selectcol1,dump(col2,1016)fromt1;


COL1


----------DUMP(COL2,1016)


--------------------------------------------------------------------------------2


Typ=1Len=4CharacterSet=AL32UTF8:d6,d0,b9,fa


1


Typ=1Len=6CharacterSet=AL32UTF8:e4,b8,ad,e5,9b,bd


对于session1,我们设置的客户端字符集为zhs16gbk。


当我们和数据库建立session后,数据库将认为这个客户端以zhs16gbk字符集编码的方


式向数据库发送字符,因为数据库的字符集是al32utf8,所以字符要以这个字符集的编码来存


储,此时oracle就会做一个字符编码转换,也就是将字符集zhs16gbk中编码为d6,d0,b9,fa 的


字符编码映射成字符集为al32utf8编码为e4,b8,ad,e5,9b,bd,在字符集al32utf8的编码里,


e4,b8,ad,e5,9b,bd对应的字符为"中国".


对于session2,我们设置的客户端字符集为al32utf8。


当我们和数据库建立session后,数据库看到客户端的字符集和数据库的字符集一致,


此时oracle将不会再对字符作转换,因为它认为两边的字符编码是一致的。而此时,我们欺


骗了数据库,尽管我们将客户端字符集设置为和数据库一致,但是其实我们使用的是


zhs16gbk字符集编码(因为此时windows使用的就是这个字符编码),对于字符"中国


",zhs16gbk字符集里对应的编码为d6,d0,b9,fa。此时,oracle不加理会的直接将这个编码保


存到了数据库中。当我们分别将这两个字符dump出来的时候,就得到下面这样的结果。


SQL>selectcol1,dump(col2,1016)fromtest;


COL1


----------DUMP(COL2,1016)


--------------------------------------------------------------------------------2


Typ=1Len=4CharacterSet=AL32UTF8:d6,d0,b9,fa


1


Typ=1Len=6CharacterSet=AL32UTF8:e4,b8,ad,e5,9b,bd


下面我们就进入到了我们最关心的地方,乱码,让我们继续我们的试验。


--session1


SQL>


SQL>insert intot1 values('中国',1);


1rowcreated.


SQL>commit;


Commitcomplete.


SQL>select*fromt1;


COL COL2


----------------------中国 1


??? 2


--session2


SQL> insert intot1 values('中国',2);


1rowcreated.


SQL>commit;


Commitcomplete.


SQL>select*fromt1;


COL COL2


----------------涓?浗 1


中国 2


session1,我们看到session2输入的字符"中国"变成了乱码"???",


session2,我们看到session1输入的字符"中国"变成了另外的字符"涓?浗",


下面我们来分析一下这中间数据库,客户端和操作系统都发生了那些事情。


上面已经讨论了:


session1输入的字符"中国" 在数据库中存储的字符编码为”e4,b8,ad,e5,9b,bd".


session2输入的字符"中国" 在数据库中存储的字符编码为”d6,d0,b9,fa".


当session1开始查询时,oracle从表中取出这两个字符,并按照字符集al32utf8和字符


集zhs16gbk的编码映射表,将它的转换成zhs16gbk字符编码,对于编码“e4,b8,ad,e5,9b,bd”,


它对应的zhs16gbk的字符编码为"d6,d0,b9,fa",这个编码对应的字符为”中国“,所以我们看到


了这个字符正常显示出来了,而对于字符集al32utf8字符编码“d6,d0,b9,fa”,由于我们用于


显示字符的windows环境使用的是zhs16gbk字符集,而在zhs16gbk字符集里面并没有对应这


个编码的字符或者属于无法显示的符号,于是使用了"?"这样的字符来替换,这就是为什么


我们看到session2输入的字符变成了这样的乱码。


当session2开始查询时,oracle从表中取出这两个字符,由于客户端(nls_lang)和数据


库的字符集设置一致,oracle将忽略字符的转换问题,于是直接将数据库中存储的字符返回


给客户端。对于编码为"d6,d0,b9,fa"的字符,返回给客户端,而客户端显示所用的字符集正


好是zhs16gbk,在这个字符集里,这个编码对应的是"中国"两个字符,所以就正常显示出来


了。对于字符编码“e4,b8,ad,e5,9b,bd”,返回到客户端後,因为在zhs16gbk里采用的是双字


节存储字符方式,所以这6字节对应了zhs16gbk字符集的3个字符,也就是我们看到的"涓?


浗".


到现在为止,我想我们基本上搞清楚了为什么日常查询时会遇到乱码的问题。


其实乱码,说到底就是用于显示字符的操作系统没有在字符编码中找到对应的字符导致


的,造成这种现象的主要原因就是:


1:输入操作的os字符编码和查询的os字符编码不一致导致出现乱码。


2:输入操作的客户端字符集(nls_lang)和查询客户端字符集(nls_lang)不同,也可能导致查


询返回乱码或者错误的字符。


还有一个问题需要解释一下:


在上面的例子中,相同的字符在不同的字符集中对应着不同的字符编码,这个通常称为


字符集不兼容或者不完全兼容,比如zhs16gbk和al32utf8,他们存储的ascii码的字符编码都


是相同的,但对于汉字却是不同的。


如果两个字符集对于相同的字符采用的相同的字符编码,我们称之为字符兼容,范围大


的叫做范围小的字符集的超级。我们通常遇到的zhs16cgb231280,zhs16gbk就是这样的情况,


后者是前者的超级。


在实际的环境中除了字符显示之外,还有其他的地方会涉及到字符集问题。比如:


1:exp/imp


2:sql*lorder


3:应用程序的字符输入


......


一个误区:


看到很多人在出现乱码的时候都首先要做的就是将客户端字符集设置和数据库一致,其


实这是没有太多根据的。


设想一下,假如数据库字符集是al32utf8,里面存储这一些中文字符,而我的客户端操作


系统是英文的,此时我将客户端的nls_lang设置成al32utf8,这样会解决问题吗?这样客户


端就能显示中文了吗?客户端就能输入中文了吗?现在客户端是英文的,它的字符集里根本


就没有汉字的编码,我们简单的修改一下客户端的字符集又有什么用?前面已经讨论了,这


个设置无非就是告诉oracle我将以什么样的字符集与数据库进行数据交换,对于解决乱码问


题毫无关系。


正确的做法是将客户端的操作系统改成支持中文字符,并将客户端字符集改成和操作系


统一致的字符集,这样才能真正的解决问题。


--作者alantany

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/8568259/viewspace-2112820/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: 链接收集
请登录后发表评论 登录
全部评论

注册时间:2011-06-01

  • 博文量
    208
  • 访问量
    92685