Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1781065
  • 博文数量: 413
  • 博客积分: 8399
  • 博客等级: 中将
  • 技术积分: 4325
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-09 10:44
文章分类

全部博文(413)

文章存档

2015年(1)

2014年(18)

2013年(39)

2012年(163)

2011年(192)

分类: Oracle

2012-10-26 16:23:58

1. 字符与编码
字符是我们看到的符号的形状,而字符的编码是在某个编码格式下的对应的数字。
而编码格式本质上是一个字符和他的编码之间对应的表格。编码和解码都是查找这个表格来实现的。

编码:即根据字符查找表格得到编码数字;
解码:即根据编码数字查找表格得到字符;

注意:我们显示的和看到的都是字符,而传输和存储的都是字符的编码
所以在存储时,是将字符查找表格得到编码,然后将编码存储在磁盘中;而在显示时,是将磁盘中的编码读出来,然后查找表格得到字符,然后将字符显示出来。

2. 软件在编码和解码时采用何种编码格式
我们知道OS有一个编码格式,那么安装在OS上的软件的编码格式有两种情况:
1)如果软件自带了编码格式,那么软件在进行编码和解码采用的就是自己的编码格式,如不Oracle server自带了各种的编码格式,那么在Oracle服务端采用它自己的编码格式,而与安装Oracle server的OS的编码格式没有关系。
2)如果软件没有自带编码格式,那么软件在进行编码和解码采用的就是OS的编码格式。比如sqlplus, pl/sql等软件在进行编码和解码时采用的格式就是其所在的OS的编码格式。

一般只有大型软件自带了编码格式,比如OS,Java虚拟机,Oracle server等。
我们可以用locale命令查看OS采用的编码:
[oracle@localhost ~]$ locale;
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

可以利用 locale -a 来得到OS支持的编码格式,即OS中拥有的字符编码的表格。
[oracle@localhost ~]$ locale -a

一个字符集,本质上是一张字符和编码对应的表格。

3. Oracle的数据库字符集 与 国家字符集
数据库字符集:是在存储char, varchar2, clob, long等类型的字符时,采用的编码格式。
国家字符集:是在存储nchar, nvarchar2, nclob等类型的字符时,采用的编码格式。一般很少使用。

我们可以查看Oracle server端的编码格式
SQL> select * from nls_database_parameters;
PARAMETER                      VALUE
------------------------------ ------------------------------
NLS_LANGUAGE                   AMERICAN
NLS_TERRITORY                  AMERICA
NLS_CURRENCY                   $
NLS_ISO_CURRENCY               AMERICA
NLS_NUMERIC_CHARACTERS         .,
NLS_CHARACTERSET               ZHS16GBK
NLS_CALENDAR                   GREGORIAN
NLS_DATE_FORMAT                DD-MON-RR
NLS_DATE_LANGUAGE              AMERICAN
NLS_SORT                       BINARY
NLS_TIME_FORMAT                HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT           DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT             HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT        DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY              $
NLS_COMP                       BINARY
NLS_LENGTH_SEMANTICS           BYTE
NLS_NCHAR_CONV_EXCP            FALSE
NLS_NCHAR_CHARACTERSET         AL16UTF16
NLS_RDBMS_VERSION              10.2.0.1.0

20 rows selected.

可见我们数据库server端的字符集是ZHS16GBK,而国家字符集是AL16UTF16。
NLS_LANGUAGE 指语言:影响Oracle返回的提示信息和错误信息采用的语言。
NLS_TERRITORY 指地区:影响Oracle返回的信息中日期等的格式。

同样我们也可以查看某个session的字符编码信息
SQL> select * from nls_session_parameters;
PARAMETER                      VALUE
------------------------------ ------------------------------
NLS_LANGUAGE                   AMERICAN
NLS_TERRITORY                  AMERICA
NLS_CURRENCY                   $
NLS_ISO_CURRENCY               AMERICA
NLS_NUMERIC_CHARACTERS         .,
NLS_CALENDAR                   GREGORIAN
NLS_DATE_FORMAT                DD-MON-RR
NLS_DATE_LANGUAGE              AMERICAN
NLS_SORT                       BINARY
NLS_TIME_FORMAT                HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT           DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT             HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT        DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY              $
NLS_COMP                       BINARY
NLS_LENGTH_SEMANTICS           BYTE
NLS_NCHAR_CONV_EXCP            FALSE

17 rows selected.

4. 字符集的命名格式
Oracle中自带的各种字符集的命名格式如下:
language + bit size + encoding
即:语言+多少位+编码格式
比如:
ZHS16GBK表示:中文简体、16位编码、GBK编码

我们一常碰到的字符集有:
US7ASCII
AL32UTF8
AF16UTF16 (国家字符集)
ZHS16GBK  (最新的中文字符集)

超级:一个字符集包含了另一个字符集的所有字符编码; 
严格超级:在超级的基础上,要求两个个字符集关于同一个字符的编码值相同;

在中国,国家字符集只能选择 AF16UTF16,没有其他的选择;而对于数据库字符集,如果我们的数据库只存储中英文数据,那么我们应该选择ZHS16GBK,如果要存储其他的字符,那么应该选择AL32UTF8。比如全球性的跨国公司,那么他的数据库字符集应该选择AL32UTF8。

Oracle支持的字符集可以用下面的命令查出来:
select * from v$nls_valid_values;
PARAMETER                      VALUE                          ISDEPRECAT
------------------------------ ------------------------------ ----------
... ...
CHARACTERSET                   UTFE                           FALSE
CHARACTERSET                   AL32UTF8                       FALSE
CHARACTERSET                   ZHT16HKSCS31                   FALSE
CHARACTERSET                   JA16EUCFIXED                   TRUE
CHARACTERSET                   JA16SJISFIXED                  TRUE
CHARACTERSET                   JA16DBCSFIXED                  TRUE
CHARACTERSET                   KO16KSC5601FIXED               TRUE
CHARACTERSET                   KO16DBCSFIXED                  TRUE
CHARACTERSET                   ZHS16CGB231280FIXED            TRUE
CHARACTERSET                   ZHS16GBKFIXED                  TRUE
CHARACTERSET                   ZHS16DBCSFIXED                 TRUE
CHARACTERSET                   ZHT32EUCFIXED                  TRUE
CHARACTERSET                   ZHT32TRISFIXED                 TRUE
CHARACTERSET                   ZHT16DBCSFIXED                 TRUE
CHARACTERSET                   ZHT16BIG5FIXED                 TRUE
CHARACTERSET                   AL16UTF16                      FALSE
... ...

5. nls_lang
因为sqlplus没有自带字符集,所以sqlplus使用的是客户端OS的字符集;而Oracle自带了字符集,那么Oracle使用自己的字符集,而与服务器OS的字符集没有关系。

当使用sqlplus将一个字符串 '中国' insert 到Oracle数据库时,sqlplus会使用其所在的OS的字符编码将 '中国' 进行编码得到编码值,然后将编码值传输到Oracle服务器;那么Oracle服务端得到编码值之后,它必须询问sqlplus客户端,知道它使用的是什么编码格式进行的编码。而sqlplus就是通过参数 nls_lang 来告诉server端,自己的编码格式。

Oracle服务端根据nls_lang知道了sqlplus客户端的编码格式,如果该编码格式与数据库的编码格式不相同,那么它会进行转码:先利用nls_lang编码格式将编码值转换成字符,然后采用数据库的编码格式将该字符转换成编码值,然后在插入到数据库中。如果nls_lang与数据库的编码格式相同,则直接将编码格式插入到数据库中。所以nls_lang参数十分重要nls_lang一定要与sqlplus使用的编码格式相同,也就是与sqlplus所在的OS的字符集一致

nls_lang的格式
NLS_LANG = language_territory.clientCharacterSet
language: 决定oracle返回给sqplus的提示信息以及错误信息等;
territory: 区域,决定日期、货币等的格式;
clientCharacterSet: 客户端使用的字符编码格式;

例如:NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
      AMERICAN是语言,AMERICA是地区, ZHS16GBK 是客户端字符集

所以nls_lang就是在sqlplus客户端和Oracle服务端充当一个传递编码格式的的作用。一定不要传递错了。
只要nls_lang与客户端的编码格式一致,就不会在使用sqlplus时发生编码错误。

6. 避免编码错误
在使用sqlplus时一定要使nls_lang与客户端的编码格式一致;

最常见的一种错误是:设置nls_lang与数据库字符集一致,而与客户端字符集不一致。
另一种常见的错误是:数据库字符集选择错了,导致插入的一些字符在该字符集中不存在,那么Oracle就会插入一些???来代替。



阅读(2696) | 评论(0) | 转发(1) |
0

上一篇:undo与事务剖析

下一篇:Oracle中的锁概述

给主人留下些什么吧!~~