`

Oracle数据库多语言文字存储解决方案[转]

阅读更多
一、关于字符集

字符集(也称字元集,Character Set)就是字符编码表(codepage),一个字符不论英文、中文、韩文等在计算机系统内存或硬盘中通过二进制的字节(Byte)保存,这个二进制的编码就是字符编码(也称内码),字符集就是字符与内码的对应(映射)表。
    因为多国语言的原因,就出现了根据本国语言制作的字符集。如使用最广泛的ASCII编码,由美国国家标准局(即ANSI)制定,适用于所有拉丁、英文字符。中国大陆使用GB2312,GBK,GB18030等字符集,这些字符集包含所有汉字字符的内码,其中GBK,GB18030称为大字符集,对繁体中文也进行了编码。香港、台湾、澳门地区使用Big5编码,Big5收录了繁体中文(有些繁体与中国大陆繁体字符有差异)的编码,不包含简体中文的字符编码。韩文使用euc-kr的字符集,韩文中也有很多汉字,所以字符集包括很多汉字字符的编码。其他如日文、俄文等都有自己国家制定的字符集,用来保证计算机系统能正确显示本国的语言文字。不同语言的字符集不具有通用性,ASCII字符集没有制定中文字符的编码,GB2312没有制定韩文字符的编码,Big5没有制定简体中文字符的编码,针对这种不兼容性,官方发布了Unicode(进一步优化的UTF7,UTF8,UTF16等)字符集,对每一种语言的每个字符制定了统一且唯一的内码,满足跨语言、跨平台的字符解码和转换处理。

字符集编码(16进制)示例:

字符/字符集
GBK
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)       字符“삼성”在韩文字符集Euc-kr中的编码是bb-ef-bc-ba,在GBK字符集中是没有“삼성”这两个字符的,也就是说bb-ef-bc-ba在Euc-kr与GBK编码对照表中是没有记录的,如果你硬是要GBK字符集来对“삼성”作出解释(解码),那GBK就用字符“?”(因韩文字符是两个字节,所以使用全角?)代替,全角?的编码在GBK中是a3-bf。
2)       汉字“物流”字符在Euc-kr中的编码是da-aa,d7-b5,这说明韩文字符集中包含了部分汉字的编码,当然这个编码与GBK字符集中“物流”两个字符的编码(ce-ef ,c1-f7)是不同的,用GBK去解释韩文字符集中“物流”两个字符,显示的结果肯定不是“物流”两个字符。同样的,在GBK中很多繁体中文字符的编码与BIG5中相同繁体中文的字符编码也是不同的,例如你在简体中文环境开发应用程序时,窗体控件使用繁体中文表示,但是在繁体OS运行应用程序,控件上的繁体中文变成了乱码或?,原因就是不同字符集同样字符的编码是不同的,解决这个问题的方法就是将应用程序使用unicode编码保存,告诉操作系统使用unicode字符集对你的应用程序中的字符进行解码。

    Windows操作系统(OS)的字符集:不同语言的OS的默认字符集是不一样的。英文OS使用ASCII字符集作为系统的字符集,简体使用GB2312,繁体使用Big5(在VB.NET中,可用System.Text.Encoding.Default.EncodingName检查OS的字符集)。Windows系统本身对系统默认的字符集有很好的支持,但是安装在OS上的应用程序却不一定这样。例如,在一个简体中文操作系统上安装了韩文版的某个应用程序,这个应用程序在开发时使用的是euc-kr字符集编码。因为OS默认的处理非Unicode程序的字符集是GB2312,在 GB2312字符集并未对任何韩文字符进行编码,在GB2312内找不到任何一个韩文字符的内码,找不到只能以“?”代替这个字符,对应的编码变成了“?”的编码,例如:“삼성”这两个韩文字符在程序运行时显示的是“?”。解决这个问题,有三种方法:1,该韩文应用程序使用Unicode编码保存。在简体环境运行时,OS使用Unicode字符集解码,只要系统安装韩文字体,就可正常显示韩文;2,将OS处理非Unicode程序使用的字符集改为euc-kr,支持韩文应用程序的解码(在control panel->Regional and Language Options 修改);3,安装微软的AppLocale工具,指定该韩文应用程序运行时使用euc-kr的字符集。
一、Oracle字符集
Oracle字符集包括两部分。一部分是Server端数据库运行实例(instance)的字符集,一部分是Oracle客户端Client的字符集。
1,  数据库实例的字符集(以Oracle 10g为例)

 
在安装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 Client字符集(NLS_LANG)
在访问Oracle的客户端安装Oracle Client过程中并没有选项选择Oracle Client的字符集,安装完毕后在注册表HKLOCAL_MACHINE\SOFTWARE\ORACLE\KEY_ORACLECLENT_HOME1\可以找到NLS_LANG键,值为当前OS的字符集。如简体系统为:ZHS16GBK,繁体系统为:MSWIN950。可见,Oracle Client(以下简称NLS_LANG)在安装过程中选择了OS的字符集作为默认的NLS_LANG字符集。
   设定NLS_LANG有三种方法:
a)      修改注册表。将HKLOCAL_MACHINE\SOFTWARE\ORACLE\KEY_ORACLECLENT_HOME1\下NLS_LANG键值改为你要设定的字符集,如将SIMPLIFIED CHINESE_CHINA.ZHS16GBK改为:SIMPLIFIED CHINESE_CHINA.AL32UTF8。但这种做法似乎无效,即使重新启动机器后,也没有生效,NLS_LANG仍使用当初安装时的OS字符集。
b)      设定环境变量。在My Computer->Properties->Advanced->Environment Variables->System Variables 新增环境变量设置,如:Variable name=NLS_LANG,Variable Value= SIMPLIFIED CHINESE_CHINA.AL32UTF8。这样NLS_LANG字符集为UTF8,这个NLS_LANG优先序高于注册表中的NLS。注意:环境变量设在系统变量中(System Vairables),而不是用户变量(User Vairables)。
c)      在应用程序运行的Process Session中设定。在程序运行之前,先通过set NLS_LANG=进程Session的字符集。例如:


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。
三、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.”

这段话告诉我们:SQL语句提交到Server之前,SQL语句中的字符串部分(不管前面有没有N’)作为语句的一部分将被用NLS_LANG定义的字符集进行编码。提交到Server端后,再被数据库字符集编码。可以推出:如果数据库字符集与客户端NLS_LANG字符集一致,在Server端就没有必要再一次编码了。



在安装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这样的字段中去
分享到:
评论

相关推荐

    Oracle数据库多语言文字存储解决方案.docx

    Oracle数据库多语言文字存储解决方案

    Oracle 数据库多语言入库问题的解决方案

    Oracle 数据库多语言入库问题的解决方案 本文通过研究Oracle 数据库如何成功实现多语言入库,给出了一种实现多国语言信 息存储的基本方法,该方法解决了非中文语言入库时出现的乱码问题。随着企业在发展过程 中业务...

    Oracle日常维护故障定位故障排除

    20由于EXP不向上兼容,语言不兼容,导致不同版本、不同字符集的数据库无法导入 21 由于创建表空间时误将其创建在以‘本地管理’,导致在表空间上的所有对象无法修改其存储参数 22 错误地在系统表空间上建无关的数据...

    常用数据库管理系统简介.docx

    常用数据库管理系统简介 目前市场上比较流行的数据库管理系统产品主要是 Oracle、旧M、Microsoft和Sybase、 mysql等公司的产品,下面对常用的几种系统做简要的介绍: Oracle Oracle数据库被认为是业界目前比较成功的...

    5.4空间数据库管理系统.pdf

    提供了类似Oracle Spatial 的数据类型和一个对象关系模式 存储多维的网格化数据和栅格层 栅格数据拥有空间参考信息 进行空间检索 对象关系数据库管理特点 3 解决了空间数据的变长记录管理问题,由数据库软 件商扩展...

    ORACLE9i_优化设计与系统调整

    §1.1 Oracle数据库结构 23 §1.1.1 Oracle数据字典 23 §1.1.2 表空间与数据文件 24 §1.1.3 Oracle实例(Instance) 24 §1.2 Oracle文件 26 §1.2.1 数据文件 26 §1.2.2 控制文件 26 §1.2.3 重做日志文件 26 §...

    Oracle SQL高级编程(资深Oracle专家力作,OakTable团队推荐)--随书源代码

    他认为对于SQL的学习是永无止境的,相信每一个查询Oracle数据库的人都需要精通SQL语言,才能写出高效的查询。他参与本书的编写就是为了帮助别人实现这一目标。 目录 封面 -11 封底 -10 扉页 -9 版权 -8 版权声明 -7...

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

    其三、职业方向多:Oracle数据库管理方向、Oracle开发及系统架构方向、Oracle数据建模数据仓库等方向。 四、 如何学习 认真听课、多思考问题、多动手操作、有问题一定要问、多参与讨论、多帮组同学 五、 体系结构 ...

    数据库管理系统(1).doc

    目前最新版本的产品 为Microsoft SQL Server 2000,它具有可靠性、可伸缩性、可用性、可管理性等特点,为用户提供完整的数据库 解决方案。 Microsoft Office 作为Microsoft Office组件之一的Microsoft Access是在...

    数据库系统的核心.doc

    数据库系统的核心 数据库系统...可以使客户选择最适合的解决方案。对开发商全力支持。 数据库的安全策略 第一,系统安全策略:包括了数据库用户管理、数据库操作规范、用户认证、操作系 统安全4个部分。 1)数

    microservices-datadriven:利用融合的Oracle数据库和多云混合云服务构建微服务的应用程序示例代码示例

    该存储库包含用于通过构建数据驱动型微服务的解决方案示例来简化微服务体系结构的示例代码,这些示例将带您逐步学习如何使用融合的创建开放平台技术堆栈,包括关系,JSON,文本,空间和图形数据,并使用多语言语言,...

    Apache ShardingSphere分布式数据库中间层生态圈 v5.3.2 alpha

    Apache ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由JDBC、Proxy和Sidecar(规划中)这3款相互独立,却又能够混合部署配合使用的产品组成。它们均提供标准化的数据分片、分布式事务和...

    xml解决方案开发实务

     XML与Access,Oracle和SQL Server等数据库不同,数据库提供了更强有力的数据存储和分析能力,例如:数据索引、排序、查找、相关一致性等,XML仅仅是展示数据。事实上XML与其他数据表现形式最大的不同是:他极其简单...

    基于python的wxpy结合mysql数据库做的一个微信娱乐机器人.zip

    这种多引擎架构使得MySQL能够适应不同业务需求,提供高度定制化的存储解决方案。 性能与可扩展性 MySQL通过高效的缓存机制、查询优化器以及对硬件资源的有效利用,保证了在高负载情况下的稳定性和快速响应。它支持...

    一个基于 go-cqhttp 开发,以 MySQL 作为数据库的 qq 群功能型机器人.zip

    这种多引擎架构使得MySQL能够适应不同业务需求,提供高度定制化的存储解决方案。 性能与可扩展性 MySQL通过高效的缓存机制、查询优化器以及对硬件资源的有效利用,保证了在高负载情况下的稳定性和快速响应。它支持...

    竞拍网后台,基于springboot、mybatis-plus、jpa、mysql。数据库已提供.zip

    这种多引擎架构使得MySQL能够适应不同业务需求,提供高度定制化的存储解决方案。 性能与可扩展性 MySQL通过高效的缓存机制、查询优化器以及对硬件资源的有效利用,保证了在高负载情况下的稳定性和快速响应。它支持...

    这是一个简单的学生管理系统网站,基于前端+flask框架+mysql数据库.zip

    这种多引擎架构使得MySQL能够适应不同业务需求,提供高度定制化的存储解决方案。 性能与可扩展性 MySQL通过高效的缓存机制、查询优化器以及对硬件资源的有效利用,保证了在高负载情况下的稳定性和快速响应。它支持...

Global site tag (gtag.js) - Google Analytics