- 浏览: 276229 次
- 性别:
- 来自: 北京
最新评论
-
gotosuzhou:
好的 谢谢分享
Spring 事务异常回滚 -
cd249745647:
哈哈
Spring MVC REST 例子 -
向日葵上的小蜜蜂:
代码都差不多贴出来了,为啥不直接提供下载呢
Spring MVC REST 例子 -
he3109006290:
我猜它应该有个算法,当出现长时间处理的情况的,它自动会启动另外 ...
netty 疑惑 -
yanghoho6:
很好, 学习了,
oracle基本的索引概念.doc
Oracle数据库字符集问题解析
经常看到一些朋友问ORACLE字符集方面的问题,我想以迭代的方式来介绍一下。
第一次迭代:掌握字符集方面的基本概念。
有些朋友可能会认为这是多此一举,但实际上正是由于对相关基本概念把握不清,才导致了诸多问题和疑问。
首先是字符集的概念。
我们知道,电子计算机最初是用来进行科学计算的(所以叫做“计算机”),但随着技术的发展,还需要计算机进行其它方面的应用处理。这就要求计算机不仅能处理数值,还能处理诸如文字、特殊符号等其它信息,而计算机本身能直接处理的只有数值信息,所以就要求对这些文字、符号信息进行数值编码,最初的字符集是我们都非常熟悉的ASCII,它是用7个二进制位来表示128个字符,而后来随着不同国家、组织的需要,出现了许许多多的字符集,如表示西欧字符的ISO8859系列的字符集,表示汉字的GB2312-80、GBK等字符集。
字符集的实质就是对一组特定的符号,分别赋予不同的数值编码,以便于计算机的处理。
字符集之间的转换。字符集多了,就会带来一个问题,比如一个字符,在某一字符集中被编码为一个数值,而在另一个字符集中被编码为另一个数值,比如我来创造两个字符集demo_charset1与demo_charset2,在demo_charset1中,我规定了三个符号的编码为:A(0001),B(0010),?(1111);而在demo_charset2中,我也规定了三个符号的编码为:A(1001),C(1011),?(1111),这时我接到一个任务,要编写一个程序,负责在demo_charset1与demo_charset2之间进行转换。由于知道两个字符集的编码规则,对于demo_charset1中的0001,在转换为demo_charset2时,要将其编码改为1001;对于demo_charset1中的1111,转换为demo_charset2时,其数值不变;而对于demo_charset1中的0010,其对应的字符为B,但在demo_charset2没有对应的字符,所以从理论上无法转换,对于所有这类无法转换的情况,我们可以将它们统一转换为目标字符集中的一个特殊字符(称为“替换字符”),比如在这里我们可以将?作为替换字符,所以B就转换为了?,出现了信息的丢失;同样道理,将demo_charset2的C字符转换到demo_charset1时,也会出现信息丢失。
所以说,在字符集转换过程中,如果源字符集中的某个字符在目标字符集中没有定义,将会出现信息丢失。
数据库字符集的选择。
我们在创建数据库时,需要考虑的一个问题就是选择什么字符集与国家字符集(通过create database中的CHARACTER SET与NATIONAL CHARACTER SET子句指定)。考虑这个问题,我们必须要清楚数据库中都需要存储什么数据,如果只需要存储英文信息,那么选择US7ASCII作为字符集就可以;但是如果要存储中文,那么我们就需要选择能够支持中文的字符集(如ZHS16GBK);如果需要存储多国语言文字,那就要选择UTF8了。
数据库字符集的确定,实际上说明这个数据库所能处理的字符的集合及其编码方式,由于字符集选定后再进行更改会有诸多的限制,所以在数据库创建时一定要考虑清楚后再选择。
而我们许多朋友在创建数据库时,不考虑清楚,往往选择一个默认的字符集,如WE8ISO8859P1或US7ASCII,而这两个字符集都没有汉字编码,所以用这种字符集存储汉字信息从原则上说就是错误的。虽然在有些时候选用这种字符集好象也能正常使用,但它会给数据库的使用与维护带来一系列的麻烦,在后面的迭代过程中我们将深入分析。
客户端的字符集。
有过一些Oracle使用经验的朋友,大多会知道通过NLS_LANG来设置客户端的情况,NLS_LANG由以下部分组成:NLS_LANG=<Language>_<Territory>.<Clients Characterset>,其中第三部分<Clients Characterset>的本意就是用来指明客户端操作系统缺省使用的字符集。所以按正规的用法,NLS_LANG应该按照客户端机器的实际情况进行配置,尤其对于字符集一项更是如此,这样Oracle就能够在最大程度上实现数据库字符集与客户端字符集的自动转换(当然是如果需要转换的话)。
总结一下第一次迭代的重点:
字符集:将特定的符号集编码为计算机能够处理的数值;
字符集间的转换:对于在源字符集与目标字符集都存在的符号,理论上转换将不会产生信息丢失;而对于在源字符集中存在而在目标字符集中不存在的符号,理论上转换将会产生信息丢失;
数据库字符集:选择能够包含所有将要存储的信息符号的字符集;
客户端字符集设置:指明客户端操作系统缺省使用的字符集。
第一次迭代:掌握字符集方面的基本概念。
有些朋友可能会认为这是多此一举,但实际上正是由于对相关基本概念把握不清,才导致了诸多问题和疑问。
首先是字符集的概念。
我们知道,电子计算机最初是用来进行科学计算的(所以叫做“计算机”),但随着技术的发展,还需要计算机进行其它方面的应用处理。这就要求计算机不仅能处理数值,还能处理诸如文字、特殊符号等其它信息,而计算机本身能直接处理的只有数值信息,所以就要求对这些文字、符号信息进行数值编码,最初的字符集是我们都非常熟悉的ASCII,它是用7个二进制位来表示128个字符,而后来随着不同国家、组织的需要,出现了许许多多的字符集,如表示西欧字符的ISO8859系列的字符集,表示汉字的GB2312-80、GBK等字符集。
字符集的实质就是对一组特定的符号,分别赋予不同的数值编码,以便于计算机的处理。
字符集之间的转换。字符集多了,就会带来一个问题,比如一个字符,在某一字符集中被编码为一个数值,而在另一个字符集中被编码为另一个数值,比如我来创造两个字符集demo_charset1与demo_charset2,在demo_charset1中,我规定了三个符号的编码为:A(0001),B(0010),?(1111);而在demo_charset2中,我也规定了三个符号的编码为:A(1001),C(1011),?(1111),这时我接到一个任务,要编写一个程序,负责在demo_charset1与demo_charset2之间进行转换。由于知道两个字符集的编码规则,对于demo_charset1中的0001,在转换为demo_charset2时,要将其编码改为1001;对于demo_charset1中的1111,转换为demo_charset2时,其数值不变;而对于demo_charset1中的0010,其对应的字符为B,但在demo_charset2没有对应的字符,所以从理论上无法转换,对于所有这类无法转换的情况,我们可以将它们统一转换为目标字符集中的一个特殊字符(称为“替换字符”),比如在这里我们可以将?作为替换字符,所以B就转换为了?,出现了信息的丢失;同样道理,将demo_charset2的C字符转换到demo_charset1时,也会出现信息丢失。
所以说,在字符集转换过程中,如果源字符集中的某个字符在目标字符集中没有定义,将会出现信息丢失。
数据库字符集的选择。
我们在创建数据库时,需要考虑的一个问题就是选择什么字符集与国家字符集(通过create database中的CHARACTER SET与NATIONAL CHARACTER SET子句指定)。考虑这个问题,我们必须要清楚数据库中都需要存储什么数据,如果只需要存储英文信息,那么选择US7ASCII作为字符集就可以;但是如果要存储中文,那么我们就需要选择能够支持中文的字符集(如ZHS16GBK);如果需要存储多国语言文字,那就要选择UTF8了。
数据库字符集的确定,实际上说明这个数据库所能处理的字符的集合及其编码方式,由于字符集选定后再进行更改会有诸多的限制,所以在数据库创建时一定要考虑清楚后再选择。
而我们许多朋友在创建数据库时,不考虑清楚,往往选择一个默认的字符集,如WE8ISO8859P1或US7ASCII,而这两个字符集都没有汉字编码,所以用这种字符集存储汉字信息从原则上说就是错误的。虽然在有些时候选用这种字符集好象也能正常使用,但它会给数据库的使用与维护带来一系列的麻烦,在后面的迭代过程中我们将深入分析。
客户端的字符集。
有过一些Oracle使用经验的朋友,大多会知道通过NLS_LANG来设置客户端的情况,NLS_LANG由以下部分组成:NLS_LANG=<Language>_<Territory>.<Clients Characterset>,其中第三部分<Clients Characterset>的本意就是用来指明客户端操作系统缺省使用的字符集。所以按正规的用法,NLS_LANG应该按照客户端机器的实际情况进行配置,尤其对于字符集一项更是如此,这样Oracle就能够在最大程度上实现数据库字符集与客户端字符集的自动转换(当然是如果需要转换的话)。
总结一下第一次迭代的重点:
字符集:将特定的符号集编码为计算机能够处理的数值;
字符集间的转换:对于在源字符集与目标字符集都存在的符号,理论上转换将不会产生信息丢失;而对于在源字符集中存在而在目标字符集中不存在的符号,理论上转换将会产生信息丢失;
数据库字符集:选择能够包含所有将要存储的信息符号的字符集;
客户端字符集设置:指明客户端操作系统缺省使用的字符集。
第二次迭代:通过实例加深对基本概念的理解
这一部分的实验数据的存取与显示都正确,好象没什么问题,但实际上却隐藏着很大的隐患。
首先,要将汉字存入数据库,而将数据库字符集设置为US7ASCII是不合适的。US7ASCII字符集只定义了128个符号,并不支持汉字。另外,由于在SQL*PLUS中能够输入中文,操作系统缺省应该是支持中文的,但在NLS_LANG中的字符集设置为US7ASCII,显然也是不正确的,它没有反映客户端的实际情况。
但实际显示却是正确的,这主要是因为Oracle检查数据库与客户端的字符集设置是同样的,那么数据在客户与数据库之间的存取过程中将不发生任何转换。具体地说,在客户端输入“东北”,“东”的汉字的编码为182(10110110)、171(10101011),“北”汉字的编码为177(10110001)、177(10110001),它们将不做任何变化的存入数据库中,但是这实际上导致了数据库标识的字符集与实际存入的内容是不相符的,从某种意义上讲,这也是一种不一致性,也是一种错误。而在SELECT的过程中,Oracle同样检查发现数据库与客户端的字符集设置是相同的,所以它也将存入的内容原封不动地传送到客户端,而客户端操作系统识别出这是汉字编码所以能够正确显示。
在这个例子中,数据库与客户端的设置都有问题,但却好象起到了“负负得正”的效果,从应用的角度看倒好象没问题。但这里面却存在着极大的隐患,比如在应用length或substr等字符串函数时,就可能得到意外的结果。另外,如果遇到导入/导出(import /export)将会遇到更大的麻烦。有些朋友在这方面做了大量的测试,如eygle研究了“源数据库字符集为US7ASCII,导出文件字符集为US7ASCII或ZHS16GBK,目标数据库字符集为ZHS16GBK”的情况,他得出的结论是 “如果的是在Oracle92中,我们发现对于这种情况,不论怎样处理,这个导出文件都无法正确导入到Oracle9i数据库中”、“对于这种情况,我们可以通过使用Oracle8i的导出工具,设置导出字符集为US7ASCII,导出后修改第二、三字符,修改 0001 为0354,这样就可以将US7ASCII字符集的数据正确导入到ZHS16GBK的数据库中”。我想对于这些结论,这样理解可能更合适一些:由于ZHS16GBK字符集是US7ASCII的超级,所以如果按正常操作,这种转换应该没有问题;但出现问题的本质是我们让本应只存储英文字符的US7ASCII数据库,非常规地存储了中文信息,那么在转化过程中出现错误或麻烦就没什么奇怪的了,不出麻烦倒是有些奇怪了。
所以说要避免这种情况,就是要在建立数据库时选择合适的字符集,不让标签(数据库的字符集设置)与实际(数据库中实际存储的信息)不符的情况发生。
下面我将引用网友tellin在ITPUB上发表的“CHARACTER SET研究及疑问”帖子,该朋友在帖子中列举了他做的相关实验,并对实验结果提出了一些疑问,我将对他的实验结果进行分析,并回答他的疑问。
实验结果分析一
实验结果分析一
QUOTE:
最初由 tellin 发布
设置客户端字符集为US7ASCII
D:\>SET NLS_LANG=AMERICAN_AMERICA.US7ASCII
查看服务器字符集为US7ASCII
SQL> SELECT * FROM NLS_DATABASE_PARAMETERS;
PARAMETER VALUE
------------------------------ ----------------------------------------
NLS_CHARACTERSET US7ASCII
建立测试表
SQL> CREATE TABLE TEST (R1 VARCHAR2(10));
Table created.
插入数据
SQL> INSERT INTO TEST VALUES('东北');
1 row created.
SQL> SELECT * FROM TEST;
R1
----------
东北
SQL> EXIT
最初由 tellin 发布
设置客户端字符集为US7ASCII
D:\>SET NLS_LANG=AMERICAN_AMERICA.US7ASCII
查看服务器字符集为US7ASCII
SQL> SELECT * FROM NLS_DATABASE_PARAMETERS;
PARAMETER VALUE
------------------------------ ----------------------------------------
NLS_CHARACTERSET US7ASCII
建立测试表
SQL> CREATE TABLE TEST (R1 VARCHAR2(10));
Table created.
插入数据
SQL> INSERT INTO TEST VALUES('东北');
1 row created.
SQL> SELECT * FROM TEST;
R1
----------
东北
SQL> EXIT
这一部分的实验数据的存取与显示都正确,好象没什么问题,但实际上却隐藏着很大的隐患。
首先,要将汉字存入数据库,而将数据库字符集设置为US7ASCII是不合适的。US7ASCII字符集只定义了128个符号,并不支持汉字。另外,由于在SQL*PLUS中能够输入中文,操作系统缺省应该是支持中文的,但在NLS_LANG中的字符集设置为US7ASCII,显然也是不正确的,它没有反映客户端的实际情况。
但实际显示却是正确的,这主要是因为Oracle检查数据库与客户端的字符集设置是同样的,那么数据在客户与数据库之间的存取过程中将不发生任何转换。具体地说,在客户端输入“东北”,“东”的汉字的编码为182(10110110)、171(10101011),“北”汉字的编码为177(10110001)、177(10110001),它们将不做任何变化的存入数据库中,但是这实际上导致了数据库标识的字符集与实际存入的内容是不相符的,从某种意义上讲,这也是一种不一致性,也是一种错误。而在SELECT的过程中,Oracle同样检查发现数据库与客户端的字符集设置是相同的,所以它也将存入的内容原封不动地传送到客户端,而客户端操作系统识别出这是汉字编码所以能够正确显示。
在这个例子中,数据库与客户端的设置都有问题,但却好象起到了“负负得正”的效果,从应用的角度看倒好象没问题。但这里面却存在着极大的隐患,比如在应用length或substr等字符串函数时,就可能得到意外的结果。另外,如果遇到导入/导出(import /export)将会遇到更大的麻烦。有些朋友在这方面做了大量的测试,如eygle研究了“源数据库字符集为US7ASCII,导出文件字符集为US7ASCII或ZHS16GBK,目标数据库字符集为ZHS16GBK”的情况,他得出的结论是 “如果的是在Oracle92中,我们发现对于这种情况,不论怎样处理,这个导出文件都无法正确导入到Oracle9i数据库中”、“对于这种情况,我们可以通过使用Oracle8i的导出工具,设置导出字符集为US7ASCII,导出后修改第二、三字符,修改 0001 为0354,这样就可以将US7ASCII字符集的数据正确导入到ZHS16GBK的数据库中”。我想对于这些结论,这样理解可能更合适一些:由于ZHS16GBK字符集是US7ASCII的超级,所以如果按正常操作,这种转换应该没有问题;但出现问题的本质是我们让本应只存储英文字符的US7ASCII数据库,非常规地存储了中文信息,那么在转化过程中出现错误或麻烦就没什么奇怪的了,不出麻烦倒是有些奇怪了。
所以说要避免这种情况,就是要在建立数据库时选择合适的字符集,不让标签(数据库的字符集设置)与实际(数据库中实际存储的信息)不符的情况发生。
实验结果分析二
这主要是因为Oracle检查发现数据库设置的字符集与客户端配置字符集不同,它将对数据进行字符集的转换。数据库中实际存放的数据为182(10110110)、171(10101011)、177(10110001)、177(10110001),由于数据库字符集设置为US7ASCII,它是一个7bit的字符集,存储在8bit的字节中,则Oracle忽略各字节的最高bit,则182(10110110)就变成了54(0110110),在ZHS16GBK中代表数字符号“6”(当然在其它字符集中也是“6”),同样过程也发生在其它3个字节,这样“东北”就变成了“6+11”。
QUOTE:
[ 更改客户端字符集为ZHS16GBK
D:\>SET NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
D:\>SQLPLUS "/ AS SYSDBA"
无法正常显示数据
SQL> SELECT * FROM TEST;
R1
--------------------
6+11
疑问1:ZHS16GBK为US7ASCII的超集,为什么在ZHS16GBK环境下无法正常显示
[ 更改客户端字符集为ZHS16GBK
D:\>SET NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
D:\>SQLPLUS "/ AS SYSDBA"
无法正常显示数据
SQL> SELECT * FROM TEST;
R1
--------------------
6+11
疑问1:ZHS16GBK为US7ASCII的超集,为什么在ZHS16GBK环境下无法正常显示
这主要是因为Oracle检查发现数据库设置的字符集与客户端配置字符集不同,它将对数据进行字符集的转换。数据库中实际存放的数据为182(10110110)、171(10101011)、177(10110001)、177(10110001),由于数据库字符集设置为US7ASCII,它是一个7bit的字符集,存储在8bit的字节中,则Oracle忽略各字节的最高bit,则182(10110110)就变成了54(0110110),在ZHS16GBK中代表数字符号“6”(当然在其它字符集中也是“6”),同样过程也发生在其它3个字节,这样“东北”就变成了“6+11”。
实验结果分析三
当客户端字符集设置为ZHS16GBK后向数据库插入“东北”,Oracle检查发现数据库设置的字符集为US7ASCII与客户端不一致,需要进行转换,但字符集ZHS16GBK中的“东北”两字在US7ASCII中没有对应的字符,所以Oracle用统一的“替换字符”插入数据库,在这里为“?”,编码为63(00111111),这时,输入的信息实际上已经丢失,不管字符集设置如何改变(如下面引用的实验结果),第二行SELECT出来的结果也都是两个“?”号(注意是2个,而不是4个)。
需要指出的是,通过“update props$ set value$='ZHS16GBK' WHERE NAME='NLS_CHARACTERSET';”来修改数据库字符集是非常规作法,很可能引起问题,在这里只是原文引用网友的实验结果。
QUOTE:
最初由 tellin 发布
用ZHS16GBK插入数据
SQL> INSERT INTO TEST VALUES('东北');
1 row created.
SQL> SELECT * FROM TEST;
R1
--------------------
6+11
??
SQL> EXIT
最初由 tellin 发布
用ZHS16GBK插入数据
SQL> INSERT INTO TEST VALUES('东北');
1 row created.
SQL> SELECT * FROM TEST;
R1
--------------------
6+11
??
SQL> EXIT
当客户端字符集设置为ZHS16GBK后向数据库插入“东北”,Oracle检查发现数据库设置的字符集为US7ASCII与客户端不一致,需要进行转换,但字符集ZHS16GBK中的“东北”两字在US7ASCII中没有对应的字符,所以Oracle用统一的“替换字符”插入数据库,在这里为“?”,编码为63(00111111),这时,输入的信息实际上已经丢失,不管字符集设置如何改变(如下面引用的实验结果),第二行SELECT出来的结果也都是两个“?”号(注意是2个,而不是4个)。
QUOTE:
更改客户端字符集为US7ASCII
D:\>SET NLS_LANG=AMERICAN_AMERICA.US7ASCII
D:\>SQLPLUS "/ AS SYSDBA"
无法显示用ZHS16GBK插入的字符集,但可以显示用US7ASCII插入的字符集
SQL> SELECT * FROM TEST;
R1
----------
东北
??
更改服务器字符集为ZHS16GBK
SQL> update props$ set value$='ZHS16GBK' WHERE NAME='NLS_CHARACTERSET';
1 row updated.
SQL> COMMIT;
更改客户端字符集为ZHS16GBK
D:\>SET NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
D:\>SQLPLUS "/ AS SYSDBA"
可以显示以前US7ASCII的字符集,但无法显示用ZHS16GBK插入的数据,说明用ZHS16GBK插入的数据为乱码。
SQL> SELECT * FROM TEST;
R1
--------------------
东北
??
更改客户端字符集为US7ASCII
D:\>SET NLS_LANG=AMERICAN_AMERICA.US7ASCII
D:\>SQLPLUS "/ AS SYSDBA"
无法显示用ZHS16GBK插入的字符集,但可以显示用US7ASCII插入的字符集
SQL> SELECT * FROM TEST;
R1
----------
东北
??
更改服务器字符集为ZHS16GBK
SQL> update props$ set value$='ZHS16GBK' WHERE NAME='NLS_CHARACTERSET';
1 row updated.
SQL> COMMIT;
更改客户端字符集为ZHS16GBK
D:\>SET NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
D:\>SQLPLUS "/ AS SYSDBA"
可以显示以前US7ASCII的字符集,但无法显示用ZHS16GBK插入的数据,说明用ZHS16GBK插入的数据为乱码。
SQL> SELECT * FROM TEST;
R1
--------------------
东北
??
需要指出的是,通过“update props$ set value$='ZHS16GBK' WHERE NAME='NLS_CHARACTERSET';”来修改数据库字符集是非常规作法,很可能引起问题,在这里只是原文引用网友的实验结果。
实验结果分析四
由于此时数据库与客户端的字符集设置均为ZHS16GBK,所以不会发生字符集的转换,第一行与第三行数据显示正确,而第二行由于存储的数据就是63(00111111),所以显示的是“?”号。
将客户端字符集设置改为US7ASCII后进行SELECT,Oracle检查发现数据库设置的字符集为ZHS16GBK,数据需要进行字符集转换,而第一行与第三行的汉字“东”与“北”在客户端字符集US7ASCII中没有对应字符,所以转换为“替换字符”(“?”),而第二行数据在数据库中存的本来就是两个“?”号,所以虽然在客户端显示的三行都是两个“?”号,但在数据库中存储的内容却是不同的。
QUOTE:
SQL> INSERT INTO TEST VALUES('东北');
1 row created.
SQL> SELECT * FROM TEST;
R1
--------------------
东北
??
东北
SQL> EXIT
SQL> INSERT INTO TEST VALUES('东北');
1 row created.
SQL> SELECT * FROM TEST;
R1
--------------------
东北
??
东北
SQL> EXIT
由于此时数据库与客户端的字符集设置均为ZHS16GBK,所以不会发生字符集的转换,第一行与第三行数据显示正确,而第二行由于存储的数据就是63(00111111),所以显示的是“?”号。
QUOTE:
更改客户端字符集为US7ASCII
D:\>SET NLS_LANG=AMERICAN_AMERICA.US7ASCII
D:\>SQLPLUS "/ AS SYSDBA"
无法显示数据
SQL> SELECT * FROM TEST;
R1
----------
??
??
??
疑问2:第一行数据是用US7ASCII环境插入的,为何无法正常显示?
更改客户端字符集为US7ASCII
D:\>SET NLS_LANG=AMERICAN_AMERICA.US7ASCII
D:\>SQLPLUS "/ AS SYSDBA"
无法显示数据
SQL> SELECT * FROM TEST;
R1
----------
??
??
??
疑问2:第一行数据是用US7ASCII环境插入的,为何无法正常显示?
将客户端字符集设置改为US7ASCII后进行SELECT,Oracle检查发现数据库设置的字符集为ZHS16GBK,数据需要进行字符集转换,而第一行与第三行的汉字“东”与“北”在客户端字符集US7ASCII中没有对应字符,所以转换为“替换字符”(“?”),而第二行数据在数据库中存的本来就是两个“?”号,所以虽然在客户端显示的三行都是两个“?”号,但在数据库中存储的内容却是不同的。
实验结果分析五
在客户端字符集设置为US7ASCII时,向字符集为ZHS16GBK的数据库中插入“东北”,需要进行字符转换,“东北”的ZHS16GBK编码为182(10110110)、171(10101011)与177(10110001)、177(10110001),由于US7ASCII为7bit编码,Oracle将这两个汉字当作四个字符,并忽略各字节的最高位,从而存入数据库的编码就变成了54(00110110)、43(00101011)与49(00110001)、49(00110001),也就是“6+11”,原始信息被改变了。这时,将客户端字符集设置为ZHS16GBK再进行SELECT,数据库中的信息不需要改变传到客户端,第一、三行由于存入的信息没有改变能显示“东北”,而第二、四行由于插入数据时信息改变,所以不能显示原有信息了。
QUOTE:
SQL> INSERT INTO TEST VALUES('东北');
1 row created.
SQL> EXIT
更改客户端字符集为ZHS16GBK
D:\>SET NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
D:\>SQLPLUS "/ AS SYSDBA"
无法显示用US7ASCII插入的字符集,但可以显示用ZHS16GBK插入的字符集
SQL> SELECT * FROM TEST;
R1
--------------------
东北
??
东北
6+11
SQL>
疑问3:US7ASCII为ZHS16GBK的子集,为何在US7ASCII环境下插入的数据无法显示?
SQL> INSERT INTO TEST VALUES('东北');
1 row created.
SQL> EXIT
更改客户端字符集为ZHS16GBK
D:\>SET NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
D:\>SQLPLUS "/ AS SYSDBA"
无法显示用US7ASCII插入的字符集,但可以显示用ZHS16GBK插入的字符集
SQL> SELECT * FROM TEST;
R1
--------------------
东北
??
东北
6+11
SQL>
疑问3:US7ASCII为ZHS16GBK的子集,为何在US7ASCII环境下插入的数据无法显示?
在客户端字符集设置为US7ASCII时,向字符集为ZHS16GBK的数据库中插入“东北”,需要进行字符转换,“东北”的ZHS16GBK编码为182(10110110)、171(10101011)与177(10110001)、177(10110001),由于US7ASCII为7bit编码,Oracle将这两个汉字当作四个字符,并忽略各字节的最高位,从而存入数据库的编码就变成了54(00110110)、43(00101011)与49(00110001)、49(00110001),也就是“6+11”,原始信息被改变了。这时,将客户端字符集设置为ZHS16GBK再进行SELECT,数据库中的信息不需要改变传到客户端,第一、三行由于存入的信息没有改变能显示“东北”,而第二、四行由于插入数据时信息改变,所以不能显示原有信息了。
分析了这么多的内容,但实际上总结起来也很简单
分析了这么多的内容,但实际上总结起来也很简单,要想在字符集方面少些错误与麻烦,需要坚持两条基本原则:
在数据库端:选择需要的字符集(通过create database中的CHARACTER SET与NATIONAL CHARACTER SET子句指定);
在客户端:设置操作系统实际使用的字符集(通过环境变量NLS_LANG设置)。
在数据库端:选择需要的字符集(通过create database中的CHARACTER SET与NATIONAL CHARACTER SET子句指定);
在客户端:设置操作系统实际使用的字符集(通过环境变量NLS_LANG设置)。
utf8 全包容了bgk ,并不是说超集和子集;
8i 的数据库 的 utf8 是 4位定长的字符编码;
9i 和以上数据库的utf8 有4位定长AL32UTF8和 不定长的 UTF8 ,都是unicode编码;
其中,utf8 编码中 字符大多是三字节的编码,一个汉字是 3字节的编码;
zhs16gbk 并不是unicode 编码,只是提供了对gbk汉字编码的支持, 一个汉字为双字节;
utf8 对于 zhs16gbk 中的所有编码都有唯一的编码以之对应,所以我说utf8 全包容了bgk;
当然,utf8作为一种unicode 编码,他还提供 global character 的支持;
假如设置得当,从 zhs15gbk 到utf8 是可以实现无损耗的字符转换的;
8i 的数据库 的 utf8 是 4位定长的字符编码;
9i 和以上数据库的utf8 有4位定长AL32UTF8和 不定长的 UTF8 ,都是unicode编码;
其中,utf8 编码中 字符大多是三字节的编码,一个汉字是 3字节的编码;
zhs16gbk 并不是unicode 编码,只是提供了对gbk汉字编码的支持, 一个汉字为双字节;
utf8 对于 zhs16gbk 中的所有编码都有唯一的编码以之对应,所以我说utf8 全包容了bgk;
当然,utf8作为一种unicode 编码,他还提供 global character 的支持;
假如设置得当,从 zhs15gbk 到utf8 是可以实现无损耗的字符转换的;
查看数据库字符集
数据库服务器字符集select * from nls_database_parameters,其来源于props$,是表示数据库的字符集。
客户端字符集环境select * from nls_instance_parameters,其来源于v$parameter,
表示客户端的字符集的设置,可能是参数文件,环境变量或者是注册表
会话字符集环境 select * from nls_session_parameters,其来源于v$nls_parameters,表示会话自己的设置,可能是会话的环境变量或者是alter session完成,如果会话没有特殊的设置,将与nls_instance_parameters一致。
客户端的字符集要求与服务器一致,才能正确显示数据库的非Ascii字符。如果多个设置存在的时候,alter session>环境变量>注册表>参数文件
字符集要求一致,但是语言设置却可以不同,语言设置建议用英文。如字符集是zhs16gbk,则nls_lang可以是American_America.zhs16gbk。
发表评论
-
ORACLE 中 SQL语句优化总结
2010-02-23 19:54 1032ORACLE 中 SQL语句优化总结 ... -
有用的v$视图脚本
2010-01-10 16:15 12031、基本的数据库信息 版本信息: select * f ... -
runstart脚本 测试两个SQL性能
2010-01-10 11:58 1249grant select on sys.v_$time ... -
spfile总结 转
2010-01-10 10:27 1363pfile(Initialization Paramete ... -
分析函数
2010-01-07 09:53 1100--row_number() SELECT ... -
Oracle常用SQL脚本
2009-12-29 22:54 1286测定数据的命中率 sel ... -
explain plan,autotrace,tkprof
2009-12-29 18:56 1823explain plan,autotrace,tkpr ... -
Oracle创建用户、表空间、导入导出 删除命令
2009-12-29 18:54 1708创建临时表空间 create temporary tab ... -
oracle分区
2009-12-22 23:27 2218分区有利于管理非常大 ... -
oracle数据类型
2009-12-22 22:35 1757oracle数据类型 Oracl ... -
oracle索引
2009-12-22 22:23 1272什么情况下应该使用B* ... -
数据库表(临时表)
2009-12-17 23:05 2247Oracle中的段(segment)是占用磁盘上存储空间的一个 ... -
redo和undo(部分引用别人)
2009-12-17 20:34 1712redo重做信息是oracle在在线重做日志文件中记录的信息, ... -
java调用存储过程
2009-12-17 19:11 996这段时间开始学习写存 ... -
Oracle Triggers
2009-12-17 19:08 1278Controlling When a Trigger Is F ... -
oracle入门
2009-12-17 19:05 13081.1 ORACLE数据库简介 Oracle简称甲骨文, ... -
Oracle中更新语句的重启动
2009-12-16 22:50 2139Oracle中更新语句的重启动 考虑一个简单的update语句 ... -
oracle深入体系结构 笔记
2009-12-16 22:48 1640... -
oracle各参数
2009-12-16 19:30 1206名称 类型 类别 ... -
pl/sql例子
2009-12-16 19:24 22811、使用游标、loop、%type、%rowtype DE ...
相关推荐
"Oracle数据库字符集问题解析" Oracle 数据库字符集问题解析是 Oracle 数据库管理系统中一个非常重要的问题。字符集是创建数据库时设定的,在创建后通常不能更改。因此,字符集的设定是个非常关键的问 题,如果...
Oracle数据库字符集问题解析
Oracle数据库字符集问题总结主要关注的是在数据迁移和交互时由于字符集差异导致的问题。字符集是决定数据库如何解释和存储字符的规则集合,对于Oracle数据库来说,它直接影响到数据的正确性和兼容性。 首先,Oracle...
- **修改数据库字符集**:更改数据库字符集是一个复杂的过程,通常需要通过备份和恢复的方式完成,或使用`ALTER DATABASE CHARACTERSET`命令,但在某些情况下(如从`US7ASCII`转换到`UTF8`)可能需要额外的步骤和...
### JDBC 连接 Oracle 字符集不同导致乱码问题解析及解决方案 #### 问题背景 在使用 JDBC(Java Database Connectivity)连接 Oracle 数据库时,可能会遇到一个常见的问题:从远程 Oracle 数据库获取的数据出现乱码...
这个小工具的工作原理可能是通过读取DMP文件的元数据部分,这些元数据包含了关于数据库字符集的信息。它可能解析Data Pump Export的输出,提取出相关的字符集信息,并以友好的方式展示给用户。这样,数据库管理员或...
在日常的软件开发与维护工作中,我们时常会遇到数据库字符集导致的数据显示错误问题。本文将详细探讨Oracle数据库中使用US7ASCII字符集时出现的乱码问题及其解决方案。 #### 一、US7ASCII字符集概述 US7ASCII是一...
为了解决这个问题,文章提出了升级Oracle数据库字符集的解决方案。通过全面测试不同字符集升级方法,最终找到了一个可行的方案,确保了生僻字能够在系统中正确显示。数据库字符集升级不仅涉及数据库本身的修改,还...
### C# 版 Oracle 数据库通用操作类解析 在现代软件开发中,数据库操作是必不可少的一部分,而 C# 结合 Oracle 数据库的应用尤为广泛。本文将深入探讨一个用于简化 Oracle 数据库操作的 C# 类——`ConnForOracle`。...
### Oracle数据库乱码问题解析与解决方案 #### 一、Oracle数据库乱码问题概述 在使用Oracle数据库的过程中,可能会遇到字符显示异常的问题,通常被称为“乱码”。这种情况会影响到数据的正确读取与处理,进而影响...
数据库字符集是在创建数据库时指定的,通常不可更改。它分为两部分:字符集和国家字符集。字符集用于存储非Unicode数据类型,如CHAR、VARCHAR2和CLOB,同时也影响对象名和PL/SQL变量的表示。国家字符集则用于存储...
首先,初始化参数文件(init.ora 或 spfile.ora)是控制 Oracle 实例行为的关键,它定义了数据库的配置选项,如内存结构的大小、日志文件位置、数据库字符集等。深入学习这一部分,我们需要了解不同类型的初始化参数...
### Oracle数据库字符集理解 首先,了解Oracle数据库字符集的基本概念至关重要。字符集是用于存储和处理文本数据的一套规则,它定义了如何表示各种字符,包括字母、数字、符号等。在Oracle中,字符集分为客户端字符...
根据提供的文件信息,本文将详细解析Oracle字符集的相关知识点,包括Oracle字符集的基本概念、配置参数、以及如何在Oracle数据库中管理和使用字符集。 ### 一、Oracle字符集概述 #### 1.1 什么是Oracle字符集 ...
- **NLS_LANG**: 设置语言环境,例如`"AMERICAN_AMERICA.ZHS16GBK"`,用于指定数据库的语言和字符集。 - **TNS_ADMIN**: TNS命名服务的管理目录,通常指向Oracle网络配置文件的路径。 - **LD_LIBRARY_PATH**: 指定...
标题中的“Clinet端工具连接Oracle数据库的jar”指的是客户端应用程序用来与Oracle数据库进行交互的Java库文件。这些jar文件是Oracle提供给开发者用于在Java应用程序中实现对Oracle数据库的连接和支持的重要组件。 ...
本文将详细介绍如何将使用US7ASCII字符集的dmp文件导入到采用ZHS16GBK字符集的Oracle数据库中,并介绍与之相关的几个关键知识点。 #### 2. 知识点详解 ##### 2.1 导入US7ASCII字符集的dmp文件至ZHS16GBK字符集的...