Oracle数据库字符集问题解析

时间:2021-02-20 06:39:41
Oracle数据库字符集问题解析
第一次迭代:掌握字符集方面的基本概念。
有些朋友可能会认为这是多此一举,但实际上正是由于对相关基本概念把握不清,才导致了诸多问题和疑问。
首先是字符集的概念。
我们知道,电子计算机最初是用来进行科学计算的(所以叫做“计算机”),但随着技术的发展,还需要计算机进行其它方面的应用处理。这就要求计算机不仅能处 理数值,还能处理诸如文字、特殊符号等其它信息,而计算机本身能直接处理的只有数值信息,所以就要求对这些文字、符号信息进行数值编码,最初的字符集是我 们都非常熟悉的ASCII,它是用7个二进制位来表示128个字符,而后来随着不同国家、组织的需要,出现了许许多多的字符集,如表示西欧字符的 ISO8859系列的字符集,表示汉字的GB2312-80、GBK等字符集。
字符集的实质就是对一组特定的符号,分别赋予不同的数值编码,以便于计算机的处理。
字符集之间的转换。字符集多了,就会带来一个问题,比如一个字符,在某一字符集中被编码为一个数值,而在另一个字符集中被编码为另一个数 值,比如我来创造两个字符集demo_charset1与demo_charset2,在demo_charset1中,我规定了三个符号的编码 为:A(0001),B(0010),?(1111);而在demo_charset2中,我也规定了三个符号的编码 为:A(1001),C(1011),?(1111),这时我接到一个任务,要编写一个程序,负责在demo_charset1与 demo_charset2之间进行转换。由于知道两个字符集的编码规则,对于demo_charset1中的0001,在转换为 demo_charset2时,要将其编码改为1001;对于demo_charset1中的1111,转换为demo_charset2时,其数值不 变;而对于demo_charset1中的0010,其对应的字符为B,但在demo_charset2没有对应的字符,所以从理论上无法转换,对于所有 这类无法转换的情况,我们可以将它们统一转换为目标字符集中的一个特殊字符(称为“替换字符”),比如在这里我们可以将?作为替换字符,所以B就转换为 了?,出现了信息的丢失;同样道理,将demo_charset2的C字符转换到demo_charset1时,也会出现信息丢失。
所以说,在字符集转换过程中,如果源字符集中的某个字符在目标字符集中没有定义,将会出现信息丢失。
数据库字符集的选择。
我们在创建数据库时,需要考虑的一个问题就是选择什么字符集与国家字符集(通过create database中的CHARACTER SET与NATIONAL CHARACTER SET子句指定)。考虑这个问题,我们必须要清楚数据库中都需要存储什么数据,如果只需要存储英文信息,那么选择US7ASCII作为字符集就可以;但是 如果要存储中文,那么我们就需要选择能够支持中文的字符集(如ZHS16GBK);如果需要存储多国语言文字,那就要选择UTF8了。
数据库字符集的确定,实际上说明这个数据库所能处理的字符的集合及其编码方式,由于字符集选定后再进行更改会有诸多的限制,所以在数据库创建时一定要考虑清楚后再选择。
而我们许多朋友在创建数据库时,不考虑清楚,往往选择一个默认的字符集,如WE8ISO8859P1或US7ASCII,而这两个字符集都没有汉字编码,所以用这种字符集存储汉字信息从原则上说就是错误的。虽然在有些时候选用这种字符集好象也能正常使用,但它会给数据库的使用与维护带来一系列的麻烦,在后面的迭代过程中我们将深入分析。
客户端的字符集。
有过一些Oracle使用经验的朋友,大多会知道通过NLS_LANG来设置客户端的情况,NLS_LANG由以下部分组成:NLS_LANG=< Language>_<Territory>.<Clients Characterset>,其中第三部分<Clients Characterset>的本意就是用来指明客户端操作系统缺省使用的字符集。所以按正规的用法,NLS_LANG应该按照客户端机器的实际情况 进行配置,尤其对于字符集一项更是如此,这样Oracle就能够在最大程度上实现数据库字符集与客户端字符集的自动转换(当然是如果需要转换的话)。
总结一下第一次迭代的重点:
字符集:将特定的符号集编码为计算机能够处理的数值;
字符集间的转换:对于在源字符集与目标字符集都存在的符号,理论上转换将不会产生信息丢失;而对于在源字符集中存在而在目标字符集中不存在的符号,理论上转换将会产生信息丢失;
数据库字符集:选择能够包含所有将要存储的信息符号的字符集;
客户端字符集设置:指明客户端操作系统缺省使用的字符集



2、数据库的字符集
字符集在创建数据库时指定,在创建后通常不能更改,所以在创建数据库时能否选择一个正确的字符集就显得尤为重要。在创建数据库时,我们可以指定字符集(CHARACTER SET)和国家字符集(NATIONAL CHARACTER SET)。
字符集用来存储:CHAR、VARCHAR2、CLOB、LONG等类型数据;用来标示诸如表名、列名以及PL/SQL变量等;SQL和PL/SQL程序单元等。
国家字符集用以存储:NCHAR, NVARCHAR2, NCLOB等类型数据。
这些设置在数据库创建时指定,我们可以看一下数据库的创建脚本:
connect SYS/change_on_install as SYSDBA
set echo on
spool E:\oracle\ora92\assistants\dbca\logs\CreateDB.log
startup nomount pfile="E:\oracle\admin\eygle\scripts\init.ora";
CREATE DATABASE eygle
MAXINSTANCES 1
MAXLOGHISTORY 1
MAXLOGFILES 5
MAXLOGMEMBERS 3
MAXDATAFILES 100
DATAFILE 'E:\oracle\oradata\eygle\system01.dbf' SIZE 250M REUSE AUTOEXTEND ON NEXT 10240K MAXSIZE UNLIMITED
EXTENT MANAGEMENT LOCAL
DEFAULT TEMPORARY TABLESPACE TEMP TEMPFILE 'E:\oracle\oradata\eygle\temp01.dbf' SIZE 40M REUSE AUTOEXTEND
ON NEXT 640K MAXSIZE UNLIMITED
UNDO TABLESPACE "UNDOTBS1" DATAFILE 'E:\oracle\oradata\eygle\undotbs01.dbf' SIZE 50M REUSE AUTOEXTEND
ON NEXT 5120K MAXSIZE UNLIMITED
CHARACTER SET ZHS16GBK
NATIONAL CHARACTER SET AL16UTF16
LOGFILE GROUP 1 ('E:\oracle\oradata\eygle\redo01.log') SIZE 10M,
GROUP 2 ('E:\oracle\oradata\eygle\redo02.log') SIZE 10M,
GROUP 3 ('E:\oracle\oradata\eygle\redo03.log') SIZE 10M;
spool off
exit;

以上用粗体显示的就是对我们至关重要的字符集设置。
在创建数据库的过程中选择你的字符集,对于简体中文平台,缺省的字符集是:ZHS16GBK
ZHS16CGB231280 CGB2312-80 16-bit Simplified Chinese MB, ASCII
ZHS16GBK GBK 16-bit Simplified Chinese MB, ASCII, UDC
其中GB2312码是*国家汉字信息交换用编码,全称《信息交换用汉字编码字符集--基本集》,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。GBK编码是1995年12月颁布的指导性规范。GBK与国家标准 GB 2312-80 信息处理交换码所对应的、事实上的内码标准兼容;同时,在字汇一级支持 ISO/IEC 10646-1 和GB 13000-1 的全部中日韩 (CJK) 汉字(20902字)。包含了更多的编码。但是我们说,ZHS16GBK 并非是ZHS16CGB231280的严格超集(虽然后者的汉字在前者中都存在,但是同样的编码在不同两个字符集中可能表达不同的汉字),所以在做数据库字符转换时仍然需要特别注意。
Oracle的字符集命名遵循以下命名规则:
<Language><bit size><encoding>
即: <语言> <比特位数><编码>
比如: ZHS · 16 ·GBK
需要说明的是,有些字符集命名违背了这个规范,Oracle8/Oralce8i中的UTF-8是第一个打破这个命名规范的字符集。我们可以看到一类字符集以AL开头,如:AL16UTF16。其中AL代表ALL,指适用于所有语言(All Languages),按照这个标准当年UTF-8本应被命名为AL24UTF8。
转自 ITPub jeffli73