
一、起因
进行这方面的总结,源于昨天同事的一个问题,同事反馈现场在进行数据库的更新时,在windows平台上执行,数据库中的中文可以正常显示,在linux机器上则为乱码,很显然,这应该与客户端与服务端的字符集有关,于是有了下面的总结;
二、何为oracle字符集
ORACLE数据库有国家字符集(national character set)与数据库字符集(database character set)之分。两者都是在创建数据库时需要设置的。国家字符集主要是用于NCHAR、NVARCHAR、NCLOB类型的字段数据,而数据库字符集使用很广泛,它用于:CHAR、VARCHAR、CLOB、LONG类型的字段数据;
ORACLE的字符集名字一般由以下部分组成:语言或区域、表示一个字符的比特位数、标准字符集名称(可选项,S或C,表示服务器或客户端)。ORACLE字符集UTF8与UTFE不符合此规定,其它基本都是这种格式。NLS_LANG=<Language>_<Territory>.<Clients Characterset>
它有三个组成部分(语言、地域和字符集),每个成分控制了NLS子集的特性。
其中:
Language: 指定服务器消息的语言, 影响提示信息是中文还是英文
Territory: 指定服务器的日期和数字格式,
Charset: 指定字符集。
如:AMERICAN _ AMERICA. ZHS16GBK
从NLS_LANG的组成我们可以看出,真正影响数据库字符集的其实是第三部分。
所以两个数据库之间的字符集只要第三部分一样就可以相互导入导出数据,前面影响的只是提示信息是中文还是英文。
我们需要搞清楚三个概念,操作系统字符集,客户端字符集,Oracle字符集:
操作系统字符集:对应的参数是LANG,这个参数应该是Oracle数据库的超集,如果操作系统不支持,那么我们的数据就会乱码。这里的操作系统指的是客户端的操作系统。服务器端的操作系统不会影响数据的存取。
数据库字符集:NLS_CHARACTERSET,可以在nls_database_parameters中查看当前数据库的字符集,安装数据库的时候选择,一般不修改,不过在新的字符集是现有字符集的严格超集的情况下可以改,其他情况下修改可能导致数据库异常。例如将UTF8字符集修改为AL32UTF8
关于子集超集的映射关系,见如下Oracle官网的文档的Binary Subset-Superset Pairs。
10gR2:
http://docs.oracle.com/cd/B19306_01/server.102/b14225/applocaledata.htm#g681463
11gR2:
http://docs.oracle.com/cd/E11882_01/server.112/e10729/applocaledata.htm#NLSPG591
12cR1:
http://docs.oracle.com/database/121/NLSPG/applocaledata.htm#NLSPG591
12cR2:
http://docs.oracle.com/database/122/NLSPG/appendix-A-locale-data.htm#NLSPG957
客户端字符集:对应的参数是NLS_LANG,如果客户端未设置,此时则取的是安装时数据库的默认参数

上图中标红部分如果一致表示数据的存储方式一致,即如果LANG、NLS_LANG、NLS_CHARACTERSET的编码是一致的如UTF8,那么数据的传输过程中不会异常,字符乱码只是显示问题。
oracle字符集实质就是按照一定的字符编码方案,对一组特定的符号,分别赋予不同数值编码的集合。Oracle数据库最早支持的编码方案是US7ASCII。
Oracle的字符集命名遵循以下命名规则:
<Language><bit size><encoding>
即: <语言><比特位数><编码>
比如: ZHS16GBK表示采用GBK编码格式、16位(两个字节)简体中文字符集
三、字符集的查看
1、查看NLS_CHARACTERSET:字符集,NLS_NCHAR_CHARACTERSET:国家字符集
数据库字符集在创建数据库时指定,在创建后通常不能更改。在创建数据库时,可以指定字符集(CHARACTER SET)和国家字符集(NATIONAL CHARACTER SET)。
A、字符集
用来存储CHAR, VARCHAR2, CLOB, LONG等类型数据
用来标示诸如表名、列名以及PL/SQL变量等
用来存储SQL和PL/SQL程序单元
B、国家字符集
用以存储NCHAR, NVARCHAR2, NCLOB等类型数据
国家字符集实质上是为oracle选择的附加字符集,主要作用是为了增强oracle的字符处理能力,因为NCHAR数据类型可以提供对亚洲使用定长多字节编码的支持,而数据库字符集则不能。国家字符集在oracle9i中进行了重新定义,只能在unicode编码中的AF16UTF16和UTF8中选择,默认值是AF16UTF16。
1.1、实例字符集
SELECT * FROM NLS_INSTANCE_PARAMETERS
主要涉及NLS_LANGUAGE、NLS_TERRITORY的值. NLS_INSTANCE_PARAMETERS其来源于v$parameter,注意:网上很多资料都说"NLS_INSTANCE_PARAMETERS 表示客户端的字符集的设置,可以是参数文件,环境变量或者是注册表",而且网上都人人亦云。记住它是表示实例的字符集环境。
1.2、数据库可用字符集参数设置
SELECT * FROM V$NLS_VALID_VALUES
1.3、数据库服务器字符集
SELECT * FROM NLS_DATABASE_PARAMETERS
NLS_DATABASE_PARAMETERS其来源于props$,是表示数据库的字符集。
1.4、客户端字符集环境
SELECT * FROM V$NLS_PARAMETERS;
SELECT USERENV('language') FROM DUAL;
USERENV、 V$NLS_PARAMETERS表示当前字符集环境。如果你在客户端执行,则表示客户端字符集环境。
1.5、会话字符集环境
SELECT * FROM NLS_SESSION_PARAMETERS;
它来源于v$nls_parameters,表示会话自己的设置,可能是会话的环境变量或者是ALTER SESSION完成,如果会话没有特殊的设置,将与 V$NLS_PARAMETERS一致。
2、 查看客户端字符集(NLS_LANG) 的方法
如果系统是LINUX或UNIX平台,则也可以通过下面命令查看(前提是必须设置了NLS_LANG,否则查出来的是空值)
$env | grep NLS_LANG
NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
$echo $NLS_LANG
AMERICAN_AMERICA.ZHS16GBK
如果系统是WINDOWS平台,则可以通过下面命令查看:
A:在运行里面,输入regedit进入注册表,HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\KEY_OraDb11g_home1\里面(最后一项与实例名、数据库版本有关系),找到NLS_LANG选项,双击它,你就可以看到相应的值。
B:echo %NLS_LANG% 。如果没有设置NLS_LANG,用这个命令看不到相关信息。
附: 设置NLS_LANG的方法
Windows平台:
临时生效:
set NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK
set NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK
永久生效:可以通过修改注册表键值永久设置
HKEY_LOCAL_MACHINE/SOFTWARE/ORACLE/KEY_XXXX_home1/NLS_LANG
UNIX & LINUX
临时生效:
export NLS_LANG=AMERICAN_AMERICA.UTF8
永久生效:可以编辑 bash_profile 文件进行永久设置
vi .bash_profile
export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
客户端的字符集要求与服务器一致,才能正确显示数据库的非Ascii字符。如果多个设置存在的时候,优先级关系为:SQL Function >Alter session>环境变量>注册表>参数文件 字符集要求一致,但是语言设置却可以不同,语言设置建议用英文。如字符集是zhs16gbk,则nls_lang可以是American_America.zhs16gbk。
四、修改oracle字符集
数据库字符集在创建后原则上不能更改。因此,在设计和安装之初考虑使用哪一种字符集十分重要。对数据库server而言,错误的修改字符集将会导致很多不可测的后果,可能会严重影响数据库的正常运行,所以在修改之前一定要确认两种字符集是否存在子集和超集的关系。一般来说,除非万不得已,我们不建议修改oracle数据库server端的字符集。特别说明,我们最常用的两种字符集ZHS16GBK和ZHS16CGB231280之间不存在子集和超集关系,因此理论上讲这两种字符集之间的相互转换不受支持。
修改字符集有2种方法可行:
通常需要导出数据库数据,重建数据库,再导入数据库数据的方式来转换。
通过ALTER DATABASE CHARACTER SET语句修改字符集,但创建数据库后修改字符集是有限制的,只有新的字符集是当前字符集的超集时才能修改数据库字符集,例如UTF8是US7ASCII的超集,修改数据库字符集可使用ALTER DATABASE CHARACTER SET UTF8。
注:本文参考了如下网友的博客,在此表示感谢,如有侵权,请告知,谢谢。
http://www.cnblogs.com/kerrycode/p/3749085.html
http://blog.csdn.net/tianlesoftware/article/details/4915223
如果你觉得有所收获并愿意继续学习的话,请扫码关注:



你也可以赞赏哟







