ORACLE 解析数据库字符集 乱码问题解决 数据库导入导出

时间:2021-10-14 06:39:33

最近将数据库字符集问题进行了分析,将一些概念和原理进行了总结,这里写一下,希望帮助到需要的朋友们。


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有关,与其他无关。