`

搞懂Oracle字符集

 
阅读更多

基本概念
 

 

字符集(Character set):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。常见的字符集有ASCII,ZHS16GB231280,ZHS16GBK等。
 

字符编码(Character Encoding):是一套法则,使用该法则能够对自然语言的字符的一个集合(如字母表或音节表),与其它的一个集合(如电脑编码)进行配对。即在符号集合与数字系统之间建立对应关系。与字符集相对应,常见的字符编码有:ASCii,ZHS16GBK,ZHT16BIG5,ZHS32GB18030等。
 

 


字符集的定义其实就是字符的集合,而字符编码则是指怎么将这些字符变成字节用于保存、读取和传输。
 

 


万国码(Unicode):包含了几乎人类所有可用的字符,每年还在不断的增加,可以看作是一种通用的字符集。它将全世界所有的字符统一化,统一编码,不会再出现字符不兼容和字符转换的问题。它有以下三种编码方式:
 
1.UTF-32编码:固定使用4个字节来表示一个字符,存在空间利用效率的问题。
 
2.UTF-16编码:对相对常用的60000余个字符使用两个字节进行编码,其余的使用4字节。
 
3.UTF- 8编码:兼容ASCII编码;拉丁文、希腊文等使用两个字节;包括汉字在内的其它常用字符使用三个字节;剩下的极少使用的字符使用四个字节。
 

 


Oracle字符集基本原理
 

 

在搞懂Oracle字符集基本原理之前,一定要先分清以下三个概念:
 

 

1. Oracle数据库服务器字符集:即Oracle以哪种字符编码存储字符,可以通过以下语句查出数据库字符集的设置。
 

SQL> select * from v$nls_parameters where parameter='NLS_CHARACTERSET';  

PARAMETER                      VALUE  
------------------------------ -----------------  
NLS_CHARACTERSET               AL32UTF8

   
 

 

2. 客户端操作系统字符集:即客户端操作系统以哪种字符编码存储字符。
 
如果是Windows,可以使用chcp命令获得代码页(code page):
 

C:\Users\xianzhu>chcp  
Active code page: 936 

 

 根据该代码页,到微软的官方文档《National Language Support (NLS) API Reference》找到其对应的字符集。

如果是Linux,字符集在/etc/sysconfig/i18n设置:
 

 

LANG="zh_CN.GB2312" (指定当前操作系统的字符集)   
SUPPORTED="zh_CN.GB2312"(指定当前操作系统支持的字符集)   
SYSFONT="lat0-sun16"(指定当前操作系统的字体) 

 

 
3. 客户端NLS_LANG参数:该参数用于向Oracle指示客户端操作系统的字符集。
 

 

有了以上3个基本概念之后,我来阐述一下Oracle字符集转换的基本原则:
 
1.设置客户端的NLS_LANG为客户端操作系统的字符集
2.如果数据库字符集等于NLS_LANG,数据库和客户端传输字符时不作任何转换
3.如果它们俩不等,则需要在不同字符集间转换,只有客户端操作系统字符集是数据库字符集子集的基础上才能正确转换,否则会出现乱码。
 


几种常见情况分析
 
下面先看一个例子,再透过现象看本质,我们会针对这个例子进行分析。
 
该例子如下:
 

1. 数据库字符集为Unicode(UTF-8编码)  
我们的数据库版本是10.2.0.4.0,数据库字符集是:  
SQL> select * from v$nls_parameters where parameter='NLS_CHARACTERSET';  
  
PARAMETER                                VALUE  
---------------------------------------- ------------------------------  
NLS_CHARACTERSET               AL32UTF8  
  
2. 客户端操作系统字符集为代码页936(字符集为ZHS16GBK)  
可以使用chcp获得windows的代码页(code page)  
C:\Documents and Settings\a105024\Desktop>chcp  
Active code page: 936  
  
3. 创建测试表  
SQL> create table test(id number,var varchar2(30));  
  
Table created.  
  
4. 插入数据  
这里在同一个操作系统启动两个session,session1的NLS_LANG设为和数据库字符集一样(即AL32UTF8):  
C:\Documents and Settings\a105024\Desktop>set nls_lang=Simplified Chinese_China.AL32UTF8  
连接数据库并插入一条数据:  
Session_1>insert into test values(1,'中国');  
  
1 row created.  
  
Session_1>commit;  
  
Commit complete.  
  
session2的NLS_LANG设为和客户端操作系统一样(即ZHS16GBK):  
C:\Documents and Settings\a105024\Desktop>set nls_lang=Simplified Chinese_China.ZHS16GBK  
连接数据库并插入一条数据:  
Session_2>insert into test values(2,'中国');  
  
1 row created.  
  
Session_2>commit;  
  
Commit complete.  
  
5. 执行查询  
在session 1上执行查询:  
Session_1>select * from test;  
  
        ID VAR  
---------- ---------------------  
         1 中国  
         2 涓   浗  
在session 2上执行查询:  
Session_2>select * from test;  
  
        ID VAR  
---------- --------------------  
         1 ???  
         2 中国 

 

 

 上面例子看起来很诡异,session1和2都能正常显示自己插入的字符串,又都不能正常显示对方插入的字符串。为了弄清楚,我们首先得知道数据库里对这两个字符串是怎么存储的。我们可以使用dump函数获得字符在数据库的编码:
 

SQL> select id,dump(var,1016) from test;  
ID DUMP(VAR,1016)  
-- ------------------------------------------------------------  
 1 Typ=1 Len=4 CharacterSet=AL32UTF8: d6,d0,b9,fa  
 2 Typ=1 Len=6 CharacterSet=AL32UTF8: e4,b8,ad,e5,9b,bd

 

 

 根据AL32UTF8的编码,“中国”两字的正确编码为(都为3个字节):
 中--e4,b8,ad
 国--e5,9b,bd
 因此session 1插入的字符串在数据库中的编码是错误的,session 2正确。这也是为什么一定要设置NLS_LANG为客户端操作系统的字符集。

但是根据上面实验我们可以知道,数据库中存储正确,并不代表客户端能正常显示;同样地,即时数据库没有正确存储,有时候客户端也能够正常显示,这又是为什么呢?别急,请听我慢慢道来:
 

 

场景1:session 1插入,session 1查询,在数据库中存储错误,但显示正确。
 插入过程:
 ”中国“两字在客户端操作系统字符集ZHS16GBK中的编码是”d6,d0,b9,fa",由于NLS_LANG和数据库字符集相同,数据库端对客户端传过来的字符编码不进行任何转换直接存入数据库,因此数据库中存储的编码也是“d6,d0,b9,fa”,
 读取过程:
 数据库端读取的编码是“d6,d0,b9,fa”,由于NLS_LANG和数据库字符集相同,客户端对数据库端传过来的字符编码不进行任何转换直接显示,编码”d6,d0,b9,fa“在客户端操作系统字符集ZHS16GBK对应的汉字为“中国”。
 从以上分析可知,虽然读取时正确的,但那是因为负负得正,实际上数据库中存储是错误的,因此要特别小心这种情况,在生成库中要避免。其实只要对它进行length操作就能轻易揭开它的假面具:
 

 

Session_1>select length(var) from test where id=1;  
  
LENGTH(VAR)  
-----------  
          3 

 

 

 得出的长度居然为3!实际的长度只是2,这会带来很多麻烦。
 
场景2:session 1插入,session 2查询,在数据库中存储错误,显示也错误。
 插入过程和场景1一样,这里就不再累述。
 读取过程:
 数据库端读取的编码是“d6,d0,b9,fa”,由于NLS_LANG和数据库字符集不同,客户端对数据库端传过来的字符编码进行转换,数据库端字符集AL32UTF8里编为“d6,d0,b9,fa”无法在客户端操作系统字符集ZHS16GBK里找到对应的编码,所以只好用?代替。
 

场景3:session 2插入,session 1查询,在数据库中存储正确,但显示错误。
 插入过程:
 ”中国“两字在客户端操作系统字符集ZHS16GBK中的编码是”d6,d0,b9,fa",由于NLS_LANG和数据库字符集不同,Oracle会进行字符编码转换,也就是将字符集ZHS16GBK里“中国”的编码“d6,d0,b9,fa"转换为字符集"AL32UTF8"里”中国“的编码”e4,b8,ad,e5,9b,bd“。
 读取过程:
 数据库端读取的编码是”e4,b8,ad,e5,9b,bd“,由于NLS_LANG和数据库字符集相同,客户端对数据库端传过来的字符编码不进行任何转换直接显示,编码”e4,b8,ad,e5,9b,bd“在客户端操作系统字符集ZHS16GBK对应的汉字为“涓   浗”(原本2个字符,现在变成了3个字符,因为ZHS16GBK的汉字以2个字节编码)。
 

场景4:session 2插入,session 2查询,在数据库中存储正确,显示也正确。
 插入过程和场景3类似。
 读取过程:
 
数据库端读取的编码是”e4,b8,ad,e5,9b,bd“,由于NLS_LANG和数据库字符集不同,客户端对数据库端传过来的字符编码进行转换,数据库端字符集AL32UTF8里”中国“两字的编码”e4,b8,ad,e5,9b,bd“转换成客户端操作系统字符集ZHS16GBK里“中国”两字的编码“d6,d0,b9,fa",并正常显示。
 
这种情况虽然经过了两次转换,都确实最正确、最推荐的方式。
 
附录:Oracle 字符集超集和子集的对应关系可查看:http://download.oracle.com/docs/cd/B19306_01/server.102/b14225/applocaledata.htm#sthref1988
 

 

结论:NLS_LANG只和客户端操作系统的字符集相关,如果客户端操作系统的字符集和数据库字符集间无法正确转换,则应该首先改变客户端终端的字符集,而不是简单地把NLS_LANG设为和数据库字符集一样。

分享到:
评论

相关推荐

    Oracle 字符集详解

    Oracle字符集是数据库管理系统Oracle中的一个重要概念,它决定了数据库如何存储和处理文本数据。字符集不仅影响着数据的准确性和一致性,还与全球化应用、数据迁移和数据交换密切相关。本篇将深入探讨Oracle字符集的...

    Oracle 修改字符集

    #### 一、理解Oracle字符集 1. **字符集定义**:字符集(Character Set)是一组符号及编码规则的集合,用于存储和处理文本数据。 2. **Oracle中的字符集类型**: - **国家字符集**(National Character Set):如`...

    Oracle字符集专题

    Oracle字符集专题是一个深入探讨Oracle数据库字符集配置、管理和常见问题解决的综合资源。这个专题涵盖了从基础概念到实际操作的多个方面,旨在帮助用户全面理解并有效处理与Oracle字符集相关的各种问题。 首先,...

    oracle字符集的查看和client字符集的修改

    ### Oracle字符集的查看与客户端字符集的修改 #### 一、Oracle字符集的基本概念 在Oracle数据库系统中,字符集(charset)是用于表示文本数据的编码方式。正确设置和管理字符集对于确保数据的一致性和正确性至关重要...

    oracle 字符集修改命令

    ### Oracle字符集修改命令详解 #### 一、引言 在Oracle数据库的管理与维护过程中,字符集的正确设置对于确保数据的正确显示与处理至关重要。由于不同的地区和语言环境对于字符编码的需求各异,因此有时可能需要...

    [Oracle] 彻底搞懂Oracle字符集

    基本概念字符集(Character set):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。常见的字符集有ASCII,ZHS16GB231280,ZHS16GBK等。字符编码...

    oracle 字符集设置

    本文将深入探讨Oracle字符集的相关概念,包括如何通过设置环境变量来修改客户端字符集,以此解决因字符集差异而导致的数据转换或损耗问题。 #### Oracle字符集的重要性 Oracle数据库通过字符集支持多种语言环境下...

    oracle修改字符集

    Oracle数据库的字符集是决定数据库如何存储和处理字符数据的关键因素。在某些情况下,由于字符集不匹配,可能会导致数据导入导出时出现问题,比如提到的.dmp文件无法正常导入到其他数据库。针对这种情况,我们可以...

    Oracle 字符集的查看和修改

    ### Oracle字符集的查看与修改详解 #### 一、Oracle字符集概述 Oracle数据库系统支持多种字符集,以便处理各种语言和地区的信息。字符集的选择对于数据的存储和处理至关重要,尤其是在全球化环境中,需要处理多种...

    修改Oracle数据库字符集的方法

    ### 修改Oracle数据库字符集的方法 #### 背景与意义 在使用Oracle数据库的过程中,可能会遇到需要更改数据库字符集的情况。这通常发生在原有字符集不能满足新的业务需求时,例如需要支持更多的语言或特殊字符。...

    oracle英文字符集插入到中文字符集

    "Oracle英文字符集插入到中文字符集"的主题聚焦于如何在不同字符集之间进行有效转换,以便在不修改客户端环境变量的情况下,实现数据的正确存储和检索。 Oracle数据库系统支持多种字符集,字符集决定了数据库如何...

    linux 下oracle中文乱码字符集设置

    Linux 下 Oracle 中文乱码字符集设置 Linux 下的 Oracle 数据库在导入数据库时出现中文乱码问题,这是因为 Oracle 数据库中的字符集格式不支持中文。解决方法是通过修改字符集格式,将其修改成支持中文的格式,这样...

    jdbc连接oracle字符集不同出现乱码

    ### JDBC 连接 Oracle 字符集不同导致乱码问题解析及解决方案 #### 问题背景 在使用 JDBC(Java Database Connectivity)连接 Oracle 数据库时,可能会遇到一个常见的问题:从远程 Oracle 数据库获取的数据出现乱码...

    更改oracle 字符集

    更改oracle 字符集,

Global site tag (gtag.js) - Google Analytics