ORACLE字符集关系

来源:互联网 发布:龙门侧铣头编程 编辑:程序博客网 时间:2024/05/21 09:27

        数据库字符集乱码是我们在数据库开发或移植的时候经常碰到的问题,以前因为项目比较进度紧,每次解决碰到的问题后都不能好好全面的整理,之后碰到该类问题还是需要花费不少的时间代价。此次正好借从oracle 11g的GBK环境移植到12c的UTF8的机会,对这个问题好好整理并记录于此,希望能对大家以后解决该类问题提供一些线索。

      

       在讲解他们之间关系之前,需要知道几个字符集概念,如上图。

       服务端:数据库字符集,操作系统字符集

      客户端:操作系统字符集,NLS_LANG。

      以我们oracle 12c数据库环境为例:

      服务端:

                  数据库字符集-AL32UTF8

                  系统字符集UTF8

      客户端

                  系统字符集GBK

                  NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

我们设计两个小例子来说明数据操作到服务端存储的数据编码流程。

开始之前我们创建一个测试表

      create table test(name varchar2(32));

先给大家讲解客户端操作数据到服务端保存的流程:insert into test values('联');

1、操作系统根据系统编码GBK将'联'编码成2个字节的GBK编码C1AA,送给sqlplus,sqlplus将C1AA数据发送给服务端。

2、oracle数据库收到编码的C1AA,并不会直接保存,而是问sqlplus这段数据的编码方式,sqlplus会将NLS_LANG的信息ZHS16GBK告诉服务端.

3、服务端与数据库字符集AL32UTF8对比发现不一致,然后根据编码表,将C1AA的GBK转码成E88194的UTF8.

4、将E88194保存。

接下来是数据库服务端到客户端的流程:select name from test;

1、oracle数据库从存储中取出E88194的数据。

2、服务端并不直接将数据给sqlplus程序,而是问sqlplus需要什么编码格式的数据。

3、sqlplus把NLS_LANG中的ZHS16GBK信息给服务端。

4、服务端获取NLS_LANG信息后与数据库编码对比,发现与自身编码不一致,根据编码表,将UTF8编码的E88194转码成GBK编码的C1AA。

5、服务端将转码后的C1AA发送给sqlplus,sqlplus直接将C1AA丢给操作系统。

6、操作系统根据系统编码GBK对C1AA解码显示‘联’。

      通过上述流程,我们可以总结:

a、 数据库服务端所在操作系统的字符集,整个流程都没有与其交互,所以服务端字符集与系统字符集没有关系。

b、客户端字符集与服务端字符集可以不一致,编码转换发生在服务端。

c、客户端字符集所要描述的是客户端传给sqlplus输入的数据的编码方式,和sqlplus传给操作系统显示的解码方式。

d、NLS_LANG在整个过程对于字符的正确保存和现实是起到决定性作用的参数。

e、NLS_LANG就是将客户端的字符集告诉服务端,所以,NLS_LANG与客户端的系统字符集要保持一致。

     通过两个过程我们知道数据库字符集如果客户端与服务端不一致,会发生编码转换的过程,且是发生在服务端,大大的增加的系统的损耗,所以,我们需要将客户端系统字符集,NLS_LANG,服务端数据库字符集,三者设为同一字符集,即客户端与服务端字符集要配置成一样的。这样也是配置的最简单,最高效的方法。


        再讲解一下EXP/IMP与字符集之间的关系。

      服务端:数据库字符集

      客户端:NLS_LANG

      文件字符集

      exp导出dmp文件,其文件的字符集由NLS_LANG决定,数据库字符集与NLS_LANG字符集是否一致,决定在生成dmp文件时是否会有转码过程。

      IMP:字符集有关属性,文件字符集与oracle字符集,二者相同,导入的时候不需要转码,两个不同,导入的时候需要转成oracle数据库的字符集。

      

0 0