1、关于字符集 html
字符集(也称字元集,Character Set)就是字符编码表(codepage),一个字符不论英文、中文、韩文等在计算机系统内存或硬盘中经过二进制的字节(Byte)保存,这个二进制的编码就是字符编码(也称内码),字符集就是字符与内码的对应(映射)表。sql
字符集编码(16进制)示例:session
字符/字符集oracle |
GBKide |
Euc-kr |
UTF8测试 |
UTF16 |
物流优化 |
ce-ef ,c1-f7 |
da-aa,d7-b5 |
e7-89-a9,e6-b5-81 |
72-69,6d-41 |
삼성 |
无 |
bb-ef ,bc-ba |
ec-82-bc,ec-84-b1 |
c0-bc,c1-31 |
注:
1)
2)
1、Oracle字符集
Oracle字符集包括两部分。一部分是Server端数据库运行实例(instance)的字符集,一部分是Oracle客户端Client的字符集。
1,
在安装Oracle数据库过程当中,能够选择数据库字符集。默认的是OS系统的字符集,如简体中文系统是GB2312,繁体系统是BIG5。Oracle对于简体系统的字符集使用ZHS16GBK,GBK是GB2312的超集,Oracle不识别GB2312,只认ZHS16GBK。此外,选择Unicode做为数据库字符集,全部存储数据都将以Unicode编码存储在数据库中,不论字段类型是Number,varchar2,DateTime等。或者也能够从字符集列表中选择其余字符集。注意到有个国家字符集的选项,并且国家字符集的选择只有unicode,这是为当数据库字符集为非Unicode时将数据存为Unicode编码时用到。好比:数据库字符集为ZHS16GBK,数据库表mer_categ的一个字段为S_merc_name,数据类型为varchar2,存入中文字符“物流”,“物流”这两个字符使用GBK字符集编码存储。经过“select dump(s_merc_name,16) from mer_categ”查询该字段在数据库中的内码获得结果是:ce,ef ,c1,f7,这与咱们在前面看到的示例表中这两个字的内码是一致的。如今,把S_merc_name这个字段类型改成nvarchar2,意味着这个字段数据的存储将使用National Charset(国家字符集)——AL16UTF16的编码存储。一样写入“物流”两个中文字符,再次查询该数据在数据库中的内码结果是:e7,89,a9e6,b5,81,这就是咱们为何使用nvarchar2做为字段类型的缘由。回过头来看,若是数据库字符集选择了Unicode,那表字段中使用nvarchar2已经没什么意义了,由于全部字段类型的数据都是使用Unicdoe编码来保存的。
查询数据库字符集的sql指令是:
“select * from v$nls_parameters”
得出结果:
NLS_LANGUAGE |
SIMPLIFIED CHINESE |
NLS_TERRITORY |
CHINA |
NLS_CURRENCY |
锟 |
NLS_ISO_CURRENCY |
CHINA |
NLS_NUMERIC_CHARACTERS |
., |
NLS_CALENDAR |
GREGORIAN |
NLS_DATE_FORMAT |
DD-MON-RR |
NLS_DATE_LANGUAGE |
SIMPLIFIED CHINESE |
NLS_CHARACTERSET |
AL32UTF8 |
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_NCHAR_CHARACTERSET |
UTF8 |
NLS_COMP |
BINARY |
NLS_LENGTH_SEMANTICS |
BYTE |
NLS_NCHAR_CONV_EXCP |
FALSE |
其中NLS_CHARACTERSET 是数据库的字符集;NLS_NCHAR_CHARACTERSET是国家字符集。
数据库的字符集在创建数据库的时候建立。目前也有方法转换字符集,但两个字符集的转换仍是存在风险,形成数据丢失或错误,不建议使用。
2,
在访问Oracle的客户端安装Oracle Client过程当中并无选项选择Oracle Client的字符集,安装完毕后在注册表HKLOCAL_MACHINE\SOFTWARE\ORACLE\KEY_ORACLECLENT_HOME1\能够找到NLS_LANG键,值为当前OS的字符集。如简体系统为:ZHS16GBK,繁体系统为:MSWIN950。可见,Oracle Client(如下简称NLS_LANG)在安装过程当中选择了OS的字符集做为默认的NLS_LANG字符集。
a)
b)
c)
Echo %nls_lang%,在这个session中,已经设定NLS_LANG字符集为ZHS16GBK。一样,你也能够新开一个CMD窗口,设定另外一种NLS_LANG字符集。这种在session中设定NLS_LANG的优先序高于系统环境变量NLS_LANG。注册表NLS_LANG、系统环境变量NLS_LANG、Session NLS_LANG的优先序是:Session NLS_LANG > 系统环境变量NLS_LANG > 注册表NLS_LANG。
3、Oracle数据库如何存储多国文字
首先,先看一个有趣的问题。咱们要保存的文字哪里来?一种方法是在屏幕上输入,输入中文时,咱们打开本身习惯的输入法,在应用程序给你提供的输入框内输入文字;还有一种方法是复制粘贴的方法,将文字从网页、文档中拷贝后再粘贴到输入框中,那问题是:输入框中的文字使用的字符集是什么?有人说,是客户端操做系统的默认字符集。好,个人操做系统是简体中文,默认系统字符集是GB2312,在输入框中输入韩文字符“삼성”,若是这两个韩文字符是用GB2312字符集解码的,输入框内应该显示两个“?”,由于GB2312字符集内没有韩文字符只能用“?”代替。可是如今这两个韩文字符在输入框内正常的显示,说明这两个韩文的字符集是支持韩文字符的字符集,是韩文字符集“euc-kr”,仍是Unicode字符集?肉眼看不出来,也许查看一下内存中输入框中文字的编码能找到答案,喜欢钻研的人能够去看一看。表面来判断,多是根据输入法使用的字符集,输入法使用什么样的字符集,输入的文字就是用的什么样的字符集。从网页上复制粘贴过来的文字,应该跟网页的字符集是一致的。其实,咱们不关心多国文字背后的字符集是用的本国字符集仍是unicode字符集,咱们关心的是多国文字如何在数据库中被正确地存取。
以oracle 10g R2 10.2.0.3 做为测试数据库版本,在数据库创建一张表:
表名称:mer_categ,商品类别表
字段 |
数据类型 |
长度 |
说明 |
S_merc_id |
Varchar2 |
20 |
分类编号 |
S_merc_name |
Varchar2 |
50 |
分类名称 |
如今要新增一个分类编号为01,分类名称为“삼성”的记录。即便SQL的初学者也会写出:
Insert into mer_catag values (‘01’,’삼성’);
这条SQL语句没有错,可是能不能把“삼성”正确的写入数据库,仅仅靠一条SQL语句是不够的,在分析各类测试环境以前,咱们看一段官方关于SQL语句中字符串字符编码的描述:
“Being part of a SQL or PL/SQL statement, the text of any literal, with or without the prefix N
, is encoded in the same character set as the rest of the statement. On the client side, the statement is in the client character set, which is determined by the client character set defined in NLS_LANG
, or specified in theOCIEnvNlsCreate()
call, or predefined as UTF -16 in JDBC. On the server side the statement is in the database character set.”
在安装oracle数据库时若是一直选择“下一步”,数据库字符集将默认使用操做系统字符集。如在简体OS下,安装Oracle Server,建立Oracle实例后,实例的数据库字符集默认是ZHS16GBK;安装客户端后,NLS_LANG默认是ZHS16GBK字符集。GBK是汉字大字符集,处理汉字简繁体均可以,因此平时使用相似:
Insert into mer_catag values (‘01’,’中国’);
Insert into mer_catag values (‘01’,’中國’);
都是正常的。可是当处理多国文字时,就不灵了。如:
Insert into mer_catag values (‘01’,’삼성’);
根据前面引用的官方描述,这条SQL语句不管是字符串部分仍是其余部分,将先被NLS_LANG定义的字符集转换,“삼성”将用GBK字符集转换,前面讲过,“삼성”转换后的字符是“??”(两个全角问号)。SQL语句变成了:
Insert into mer_catag values (‘01’,’??’);
在server端,因数据库字符集与NLS_LANG一致,SQL语句再也不进行字符集转换,执行SQL后,数据库存储了两个全角“?”。用select dump(s_merc_name,16) from mer_categ验证一下,获得结果是:Typ=1 Len=4: a3,bf,a3,bf。“a3,bf”就是全角”?”的GBK编码。两个韩文字符被看成”?”存在了数据库中,查询出的固然也是”?”。因此,不对oracle字符集进行配置,不能正确处理多国文字的存储。
客户端的NLS能实现对多国文字进行正确字符集转换的话,毫无疑问是选择Unicode字符集。用set NLS_LANG =SIMPLE CHINESE.AL32UTF8能够修改客户端的NLS为UTF8字符集,仍是以
Insert into mer_catag values (‘01’,’삼성’);
为例,在客户端,这条SQL语句使用UTF8字符集作了编码转换,韩文字符“삼성”的编码转为:“ec-82-bc,ec-84-b1”(UTF8编码)。下一步,关键看Server端的数据库字符集了,若是数据库字符集仍为GBK,也就是说,“삼성 ”要做UTF8->GBK的转码,能转成功吗?显然不能够,连个韩文字符又被全角“?”代替了。在server端,SQL语句被转成了:
Insert into mer_catag values (‘01’,’??’);
数据库又存了两个全角“?”。怎么办?Server端能不能不做字符集转换?前面提到,若是数据库字符集与客户端NLS_LANG字符集一致,在Server端就没有必要再一次编码了。好,那就在Server端将数据库字符集设为UTF8,韩文字符“삼성”就以UTF8的字符编码存到数据库里了。验证一下,select dump(s_merc_name,16) from mer_categ,结果是:Typ=1 Len=6: ec,82,bc,ec,84,b1。这个结果与前面看到的UTF8编码是一致的。因此,当数据库字符集与NLS_LANG(客户端)都设为UTF8字符集时,能够解决多国文字正确存储的问题。
彷佛将数据库字符集与NLS_LANG都设为UTF8的作法未获得普遍应用,缘由是大多数的应用不存在使用多国语言的问题?没作过相关调查。除此以外,使用UTF8存储数据占用更多的空间是事实存在的,一个汉字字符UTF8使用三个字节存储,而在GBK中使用两个字节,用GBK做为数据库字符集存储汉字更经济实惠些。最后,任何存入数据库的数据都先通过UTF8的转码再存储,必然带来效能的损失。那能不能区别对待存储的数据呢?例如只针对存在多国字符的数据使用Unicode字符集存储呢?这就是国家字符集(National Chartset)存在的缘由。国家字符集是那些存放在NCHAR,NVARCHAR2,NCLOB字段中的数据的Unicode字符编码集,Oracle 10g使用AL16UTF16字符集做为默认的数据库国家字符集。如何将多国文字存储到NVARCHAR2这样的字段中去?