最近将数据库字符集问题进行了分析,将一些概念和原理进行了总结,这里写一下,希望帮助到需要的朋友们。
1、什么是NLS_Lang
NLS_LANG是环境变量,包括3部分NLS参数:NLS_LANGUAGE, NLS_TERRITORY, NLS_CHARACTERSET,需要在启动SQLPLUS等工具之前设置;这是对于客户端而言的。
影响这个参数的包括操作系统的NLS_Lang的环境变量设置。
NLS_LANGUAGE主要控制SESSION中提示消息的语言,可以使用ALTER SESSION在SQLPLUS里面设置;
NLS_TERRITORY主要控制SESSION中的日期和货币等本地化参数的现实格式,也可以像NLS_LANGUAGE一样在 SESSION 里面设置;
NLS_CHARACTERSET控制客户端的字符集,不能在SESSION里面进行设置,只能通过NLS_LANG环境变量的方式进行设置。
2、 NLS_Lang的格式:
NLS_LANG=<language>_<Territory>.<Clients CharacterSet>
各部分含义如下:
LANGUAGE指定:
-Oracle消息使用的语言
-日期中月份和日显示
TERRITORY指定
-货币和数字格式
-地区和计算星期及日期的习惯
CHARACTERSET:
-控制客户端应用程序使用的字符集
3、什么是字符集?
字符集就是按照一定的字符编码方案,对一组特定的符号,分别赋予不同数值编码的集合。
格式为<语言><比特位数><编码 >比如: ZHS16GBK表示采用GBK编码格式、16位(两个字节)简体中文字符集
数据库初始化参数字符集,在建数据库前指定的字符集,建立后通常不能修改,如果修改可以用命令alter database set character set 不过这样修改有一定的危险,有可能会出现乱码超成数据的丢失,而且修改后的字符集一定是修改前的超集。
如果未指定建库时会依赖os的设置。session级作用域只是影响那个连接.
4、数据库字符集的查看:
nls_database_parameters;数据来源props$内部表,表示数据库的字符集信息,与参数文件和环境变量都没有关系。
nls_instance_parameters:数据来源v$system_parameter视图,表示实例的字符集信息,和实例启动参数文件有关,如不指定,那么参考nls_database_parameters数值。
nls_session_parameters:根据客户端的环境变量而来,也可以通过alter session更改,如不指定,那么继承nls_instance_parameters数值。(客户端的参数变量)
select view_name,text from dba_views where view_name like 'NLS%';通过此命令,查看表或者视图的来源。
5、客户端 NLS_LANG 的设置方法
Windows:
# 常用中文字符集
set NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK
# 常用unicode字符集
set NLS_LANG=american_america.AL32UTF8
可以通过修改注册表键值永久设置
HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\HOMExx\NLS_LANG
Unix:
# 常用unicode字符集
export NLS_LANG=american_america.AL32UTF8
# 常用中文字符集
export NLS_LANG="Simplified Chinese_china".ZHS16GBK
可以编辑 bash_profile 文件进行永久设置
vi .bash_profile
NLS_LANG="Simplified Chinese_china".ZHS16GBK export NLS_LANG
# 使 bash_profile 设置生效
source .bash_profile
所以说,在安装数据库时要规定字符集,不规定则采用OS的字符集。如果想更改数据库字符集,那么要在导数据之前,或者修改的字符集是个超集。
否则,如果数据库有数据,强行修改字符集,会造成数据的乱码。
6、示例说明字符集的来龙去脉:
例如:
在客户端与服务器通信的过程中,步骤如下:
字符集与客户端操作系统、客户端NLS_Lang、数据库字符集有关系
比如客户端操作系统、NLS_Lang字符集为ZHS16GBK,数据库字符集为UTF-8
1、客户端发出insert into test(id,name) values (1,"xx"); 由操作系统进行ZHS16GBK编码,发给数据库;数据库参考客户端的NLS_Lang设置知道发过来的命令编码是ZHS16GBK,于是数据库内部将字符进行转换:ZHS16GBK编码-->文字-->UTF-8编码,存储到数据库中。
2、读取数据时,select * from test; 数据库根据本身的字符集产生结果,参考客户端的NLS_Lang设置进行转码:UTF-8编码-->文字-->ZHS16GBK编码,最后发送给客户端操作系统,客户端操作系统根据本身的ZHS16GBK编码表,最后显示查询结果。
由此可知,最佳的方式就是客户端OS字符集==NLS_Lang设置==数据库字符集
NLS_Lang的设置 与 客户端OS字符集要一致,要一致,否则会出现乱码。
7、数据库导入导出时,字符集编码来龙去脉:
EXP导出时:
EXP时,起作用的有Oracle数据库的字符集和客户端操作系统参数NLS_LANG两项,这时服务器与客户端操作系统字符集都不起作用。如果客户端操作系统参数NLS_LANG与Oracle数据库的字符集相同,那就直接导出,不需要转码,并且导出文件的字符集与上述两项一样;如果客户端操作系统参数NLS_LANG与Oracle数据库的字符集不同,那么导出时Oracle数据库会将数据文件从Oracle数据库的字符集编码格式转码成客户端操作系统参数NLS_LANG指定的编码格式。
IMP导入时:
IMP时,起作用的仍然是两项,一项是DMP文件第二第三字节指定的字符集,另外一项是Oracle数据库的字符集。两个相同就不需要转码,两个不同就转成Oracle数据库字符集指定的编码格式。
分析:
其实也就是数据库只和客户端的NLS_Lang设置交互,因为要用类似PLSQL工具显示会牵扯到客户端操作系统字符集,否则类似EXP和IMP只跟NLS有关,与其他无关。