linux环境下字符集:
[root@single ~]# locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
#export NLS_LANG=american_america.zhs16gbk
windows环境下字符集:
C:\Users\Martin>chcp
活动代码页: 936
C:>set NLS_LANG=american_america.zhs16gbk
字符集分类:
操作系统字符集
Oracle软件字符集
Sql developer软件带字符集,如果软件没有字符集,则使用操作系统字符集
SYS AS SYSDBA@ORCL>desc t2;
Name Null? Type
ID NUMBER(38)
NAME VARCHAR2(20)
ID例是数字列,不需要使用字符集
NAME列是VARCHAR2表,需要使用字符集来转换。
字符集的作用和含义:
字符编码
使用场合
数据库字符集,以下类型要使用字符集。
1. 用来存储CHAR,VARCHAR2,CLOB,LONG等类型数据
2. 用来标示诸如表名,列名以及PL/SQL变量等
3. 用来存储SQL和PL/SQL程序单元等
国家字符集:
用来存储NCHAR,NVARCHAR2,NCLOB等类型数据,如果没有这些类型的数据,则不需要使用国家字符集。
SYS ASSYSDBA@ORCL>desc t3;
Name Null? Type
-----------------------------------------------------------------------------------
ID NUMBER
NAME NVARCHAR2(20)
客户端OS字符集,NLS_LANG设置,服务端OS字符集,ORACLE数据库字符集
字符集之间的关系
正确设置字符集
字符集出现问题以后的判断流程
存储的是错误的字符集
存储是的正确的字符集
Locale locale –a,chcp
字符集其实就是“字符”和“编码”的一张对照表
字符集原理:
字符集就是一个表,有两列,
左边的列是要存储的字符,比如中文字符”阮胜昌”
右边的列是一个编码,也就是计算机里面存储的数字。因为计算机里面只能存储数字,不能存储字符。
所以字符集是我们所能看到的字符与字符对应的编码的对应表。
字符集命名:
ORACLE的字符集命令遵循以下命名规则:
<Language><bit size><encoding>
即:<语言><比特位数><编码>
比如:ZHS16GBK表示采用GBK编码格式,16位(两个字节),简体中文字符集
US7ASCII #只能存储美国人使用的字符,26个字母,数字,运算符号(+-*/),总量不超过128个字符
ZHS16CGB231280 #中文字符集,是国标,比较老了
ZHS16GBK #最新的中文字符集,是字符集Zhs16CGB231280的超集,不是严格超集
AF16UTF16#国家字符集
unicode字符集:
AL32UTF8 #最新的UTF8字符集(国际型企业,即有中文字符,也有其它国家的字符)
UTF8 #比较老,字符集不全面
注:实际生产环境,如果确定数据库只是中国人用(只有中英文相关字符)的话,就采用ZHS16GBK..
数据库安装过程中,会选择确认下面两个字符集:
1.数据库字符集:数据库需要存储多国语言选择AL32UTF8,只有中英文选择ZHS16GBK
2.国家字符集 一般都选用AL16UTF16
NLS_LANG=<language>_<territory>.<clientcharacter set>
Language:显示oracle消息,校验,日期命名,是用中文显示还是英文显示
Territory:指定默认日期,数字,货币等格式
Clientcharacter set:指定客户端将使用的字符集
例如:NLS_LANG=AMERICAN_AMERICA.US7ASCII
AMERICAN:是语言,AMERICA是地区,US7ASCII是客户端字符集
Oracle提供若干NLS参数定制数据库和用户以适应本地格式,例如有NLS_LANGUAGE,NLS_DATE_FORMAT,NLS_CALENDER等,可以通过查询以下数字字典或v$视图查看。
NLS_DATABASE_PARAMETERS –显示数据库当前NLS参数取值,包括数据库字符集取值
NLS_SESSION_PARAMETERS -显示由NLS_LANG设置的参数,或经过alter session改变后的参数值(不包括由NLS_LANG设置的客户端字符集)
NLS_INSTANCE_PARAMETE -显示由参数文件init<SID>.ora定义的参数
V$NLS_PARAMETERS -显示数据库当前NLS参数取值。
查看数据库字符集:用得多
SYS AS SYSDBA@ORCL>select * fromnls_database_parameters where PARAMETER='NLS_CHARACTERSET';
PARAMETER VALUE
NLS_CHARACTERSET AL32UTF8
查看国家字符集:用得少,做为数据库字符集的补充
SYS AS SYSDBA@ORCL>select * fromnls_database_parameters where PARAMETER='NLS_NCHAR_CHARACTERSET';
PARAMETER VALUE
NLS_NCHAR_CHARACTERSET UTF8
查看当前session使用的字符集:
SYS AS SYSDBA@ORCL>select * from nls_session_parameters;
SYS AS SYSDBA@ORCL>select userenv('language') fromdual;
USERENV('LANGUAGE')
-------------------------------------------------
SIMPLIFIED CHINESE_CHINA.AL32UTF8
SYS AS SYSDBA@ORCL>select nls_charset_name(to_number('0354','xxxx'))from dual;
NLS_CHARSET_NAME(TO_NUMBER('0354','XXXX'))
----------------------------------------------
ZHS16GBK
SYS AS SYSDBA@ORCL>! echo $NLS_LANG
SIMPLIFIED CHINESE_CHINA.UTF8
SYS AS SYSDBA@ORCL>select to_char(nls_charset_id('ZHS16GBK'),'xxxx')from dual;
TO_CHAR(NLS_CHARSET_ID('ZHS16GBK'),'XXXX')
------------------------------------------------------------------------------------------------------------------------------------------------------
354
查看系统支持的字符集:
SYS AS SYSDBA@ORCL>select * from V$NLS_VALID_VALUES;
sql*plus客户端(设置原则:与所在操作系统字符集一致):
sqlplus 没有字符集,他引用操作系统字符集
sqldeveloper 这个软件有字符集,所有不用操作系统字符集
oracle有字符集,所有oracle不用操作系统字符集
总结:如果oracle client如果有字符集,以软件字符集为主,不会用操作系统的字符集,所有字符集的转换都在oracle内部完成的。
客户端字符集配置:(通过配置客户端字符集,oracle就知道客户端用什么字符集编码。)
windows:一般都是gbk,即chcp结果为936
c:>set NLS_LANG=american_america.zhs16gbk
语言和地区为中文中国的话,set NLS_LANG=simplifiedchinese_china.zhs16gbk
linux:一般为utf-8,即echo $LANG 结果为en_US.UTF-8 或zh_CN.UTF-8
#export NLS_LANG=american_america.utf8
以下是错误的字符集配置:
原则:客户端的NLS_LANG配置的字符集要与客户端软件或客户端操作系统的字符集要一样
ORACLE不管是存数据还是取数据,都要向客户端询问,对方传过来的编码是通过什么字符集转换的。
如果数据库字符集与客户端的字符集一样,ORACLE不会发生字符集转换,
如果数据库字符集与客户端的字符集不一样,ORACLE会发生这符集转换。
以下图的客户端字符集与NLS_LANG字符集不一样,这是错误的,正常的配置是NLS_LANG字符集要配置成与客户端服务器或客户端软件的字符集一样。
上图错误的原因:
客户端在varchar2等类型的列上存一个字符,这时在客户端会将字符转换成编码A4。这时将这个A4发送到ORACLE服务端,这时ORACLE就会问,这个A4编码中用什么字符集编码的,因为这时客户端的NLS_LANG字符集为WE8MSWIN1252,所以oracle就认为客户端的字符集为WE8MSWIN1252,而不是实际的WE8ISO8859P15。这时oracle看了一下数据库的字符集是AL32UTF8,与客户端的字符集WE8MSWIN1252,所有ORACLE会先将A4这个编码用WE8MSWIN1252字符集转换成A4对应的字符。再将字符通过AL32UTF8转换成编码C2A4,ORACLE就直接存这个转换好的编码C2A4。
当客户端读取数据库的字符时,ORACLE返回以AL32UTF8字符集对应的编码C2A4,ORACLE查看到NLS_LANG的字符集为WE8MSWIN1252,与数据库的字符集不一样。所以ORACLE会将C2A4先通过AL32UTF8转换为字符,再用这个字符通过WE8MSWIN1252转换成编码。这时客户端看到的就是这个编码,但这时通过WE8ISO8859P15字符集解析这个编码时得不到原来的字符,这时的字符就产生的乱码。
下图的NLS_LANG字符集与数据库的字符集一样,与客户端的字符集不一样。
上图错误的原因:
客户端将字符编码后得到A4编码,这时客户端NLS_LANG配置为UTF8,而数据库的字符集也是UTF8,所以当将这个编码传到数据库时,ORACLE看到客户端的NLS_LANG的字符集与数据库的字符集一样,所有oracle不会转换,而是直接将编码A4存入数据库。
测试:
客户端Linux,系统字符集为zh_CN.UTF-8
正确设置:
#export LANG=zh_CN.UTF-8
#export NLS_LANG=american_america.utf8
[oracle@oracle ~]$ echo $NLS_LANG
american_america.utf8
[oracle@oracle ~]$ echo $LANG
zh_CN.UTF-8
SYS AS SYSDBA@ORCL>select * from t3;
ID NAME
---------- --------------------
1 阮胜昌
commit;
查看字符对应的编码:这个编码就是oracle存储下来的。
SYS AS SYSDBA@ORCL>select id,name,dump(name,1016) fromt3;
ID NAME
---------- --------------------
DUMP(NAME,1016)
------------------------------------------------------------------------------------------------------------------------------------------------------
1 阮胜昌
Typ=1 Len=9 CharacterSet=UTF8: e9,98,ae,e8,83,9c,e6,98,8c #以16进制显示
select id,name,dump(name,1010) from t3; #以10进制显示
Typ=1 Len=9 CharacterSet=UTF8:233,152,174,232,131,156,230,152,140
select id,name,dump(name,1008) from t3; #以8进制显示
Typ=1 Len=9 CharacterSet=UTF8:351,230,256,350,203,234,346,230,214
错误配置1:
[oracle@oracle ~]$ echo $LANG
en_US.UTF-8
[oracle@oracle ~]$ echo $NLS_LANG
SIMPLIFIED CHINESE_CHINA.UTF8
SYS AS SYSDBA@ORCL>select id,name from t3;
ID NAME
---------- --------------------
1 껨莜?
错误配置2:
#export NLS_LANG=american_america.zhs16gbk
select dump('靖宇',1016) from dual;
insert into t2 values (2,'靖宇');
commit;
注意:字符集设置错误导致库中存储的就是错误的编码,这个几乎是不可逆的`一定要慎重仔细设置好字符集。
查看字符:阮胜昌字符正确的编码:
SYS AS SYSDBA@ORCL>select dump('阮胜昌',1016) from dual;
DUMP('阮胜昌',1016)
Typ=96 Len=9 CharacterSet=AL32UTF8:e9,98,ae,e8,83,9c,e6,98,8c
insert into t2 values (2,'阮胜昌');
commit;
服务器上oracle字符集
如何确定当前字符集设定,何时可以更改字符集。
SYS AS SYSDBA@ORCL>select userenv('language') fromdual;
USERENV('LANGUAGE')
AMERICAN_AMERICA.AL32UTF8
查看系统的字符集:
select * from v$nls_parameters;
了解超集,严格超集的概念,确定是否可以更改字符集。Oracle不建议后期更改数据库字符集!
服务器操作系统字符集(暂时忽略)
ps:
1.因为sql*plus 本身没有字符集,依赖于所在操作系统的字符集,而在远端linux上的oracle也是无法直接访问到windows上的字符集,所以依靠sql*plus的NLS_LANG设置来辨别。
2.因为oracle软件本身有字符集,当软件有自己的字符集时,就不用操作系统的字符集,所以服务器操作系统字符集的因素可以暂时忽略。