oracle数据库字符集
admin
2023-05-30 07:02:17
0次

我用的数据库是oracle11.2.0.4,数据库字符集是al32utf8。

客户端就是同一台机器的windows 7

用window7的客户端连接

查看windows客户端中文字符



虚拟机   192.168.10.5    数据库是test1    数据库字符集是al32utf8。


C:\Users\Administrator>echo %NLS_LANG%             -------查看客户端字符命令

SIMPLIFIED CHINESE_CHINA.AL32UTF8  


set NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK       -----设置客户端字符命令



数据库是test1   ,数据库字符集是al32utf8。



--session 1 设置客户端字符集为 zhs16gbk(修改注册表nls_lang项的characterset 为zhs16gbk) 向表中插入两个中文字符。



C:\Users\Administrator>echo %NLS_LANG%

SIMPLIFIED CHINESE_CHINA.ZHS16GBK


C:\Users\Administrator>sqlplus sys/oracle@test1 as sysdba;      


SQL> create table test(col1 number(1),col2 varchar2(10));

   SQL> insert into test values(1,'中国'); --1为session 1的标记

        1 row created.

        SQL> commit;

        Commit complete.  

        

SQL> create table test(col1 number(1),col2 varchar2(10));


表已创建。


SQL>  insert into test values(1,'中国');


已创建 1 行。


SQL>        

        

     

     

        

-session 2 设置客户端字符集 al32utf8(修改注册表nls_lang项的characterset 为al32utf8),与数据库字符集相同。 向表中插入两个和session 1相同的中文字符。        

  

C:\Users\Administrator>echo %NLS_LANG%

SIMPLIFIED CHINESE_CHINA.AL32UTF8


C:\Users\Administrator>sqlplus sys/oracle@test1 as sysdba;


SQL*Plus: Release 11.2.0.1.0 Production on 鏄熸湡涓 11鏈?28 10:35:33 2016


Copyright (c) 1982, 2010, Oracle.  All rights reserved.



杩炴帴鍒?

Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options


SQL>





  SQL> insert into test values(2,'中国'); --2为session 2的标记

        1 row created.

        SQL> commit;

        Commit complete.


--session 1


       SQL> select * from test;


      COL1 COL2

---------- --------------------

         1 中国

         2 ???    

                                                                  

--session 2

     SQL> select * from test;


      COL1 COL2

---------- ----------

         1 涓浗

         2 中国


SQL>

                 

 

 

 从session 1和session 2的结果中可以看到,相同的字符(注意,我指的是我们看到的,显示为相同的字符 中国),在不同的字符集输入环境(客户端环境变量)下,显示成了乱码。    

   在zhs16gbk字符集的客户端,我们看到了utf8字符集客户端输入的相同的中文变成了乱码-->col1=2的col2字段

SQL> select * from test;


      COL1 COL2

---------- --------------------

         1 中国

         2 ???

   

   

   

  在utf8字符集客户端,我们看到zhs16gbk字符集的客户端输入的中文变成了另外的字符  -->col1=1的col2字段   

  

  SQL> select * from test;


      COL1 COL2

---------- ----------

         1 涓浗      -----三个字符

         2 中国

         

         

 

 

SQL> select col1,dump(col2,1016) from test;


      COL1

----------

DUMP(COL2,1016)

-------------------------------------------------------------


         1

Typ=1 Len=6 CharacterSet=AL32UTF8: e4,b8,ad,e5,9b,bd


         2

Typ=1 Len=4 CharacterSet=AL32UTF8: d6,d0,b9,fa        



不同的客户端输入的中文字符,在数据库中存储的字符编码不一致。



session 1 输入的字符"中国" 在数据库中存储的字符编码为”e4,b8,ad,e5,9b,bd".

session 2 输入的字符"中国" 在数据库中存储的字符编码为”d6,d0,b9,fa".


会话一、

中国-------e4,b8,ad,e5,9b,bd     数据库发现客户端16gbk跟数据库端的utf8字符不一致    做了字符转换  首先将客户端 中国 16gbk的(双字节)编码转成utf8(三字节编码) 然后存储下来。 


会话二、

中国-------d6,d0,b9,fa           数据库发现客户端utf8跟数据库端的utf8字符一致      欺骗了数据库端,不做字符转换,直接以16gbk(双字节)的字符编码存储到数据库(utf8数据库编码为三字节)中。



              

session 1 输入的字符"中国" 在数据库中存储的字符编码为”e4,b8,ad,e5,9b,bd"

session 2 输入的字符"中国" 在数据库中存储的字符编码为”d6,d0,b9,fa"



数据库看到客户端的字符集和数据库的字符集一致,此时oracle将不会再对字符作转换,因为它认为两边的字符编码是一致的。而此时,

我们欺骗了数据库,尽管我们将客户端字符集设置为和数据库一致,但是其实我们使用的是zhs16gbk字符集编码(因为此时windows使用的就是这个字符编码),

对于字符"中国",zhs16gbk字符集里对应的编码为d6,d0,b9,fa。此时,oracle不加理会的直接将这个编码保存到了数据库中。




客户端的字符集的作用就是告知数据库端传输的字符编码,跟数据库端的字符集一致就直接存储,不一致就字符转换。




查询是存储的字符转换的逆过程。

session1查询

SQL> select * from test;


      COL1 COL2

---------- --------------------

         1 中国

         2 ???

         



当session 1开始查询时,oracle从表中取出这两个字符,并按照字符集al32utf8和字符集zhs16gbk的编码映射表,将它的转换成zhs16gbk字符编码,对于编码“e4,b8,ad,e5,9b,bd”,

它对应的zhs16gbk的字符编码为"d6,d0,b9,fa",这个编码对应的字符为”中国“,所以我们看到了这个字符正常显示出来了,

而对于字符集存储的al32utf8字符编码“d6,d0,b9,fa”,

由于我们用于显示字符的windows环境使用的是zhs16gbk字符集,而在zhs16gbk字符集里面并没有对应这个编码的字符或者属于无法显示的符号,utf8---16gbk 转换找不到

于是使用了"?"这样的字符来替换,这就是为什么我们看到session 2输入的字符变成了这样的乱码。






session2查询

SQL> select * from test;


      COL1 COL2

---------- ----------

         1 涓浗

         2 中国

SQL>



当session 2开始查询时,oracle从表中取出这两个字符,由于客户端(nls_lang)和数据库的字符集设置一致,oracle将忽略字符的转换问题,

于是直接将数据库中存储的字符返回给客户端。对于编码为"d6,d0,b9,fa"的字符,返回给客户端,而客户端显示所用的字符集正好是zhs16gbk,在这个字符集里,########(虽然客户端变成ut8,但是转换回来还是以16gbk的,windows依然是16gbk。)

这个编码对应的是"中国"两个字符,所以就正常显示出来了。

对于字符编码“e4,b8,ad,e5,9b,bd”,返回到客户端後,因为在zhs16gbk里采用的是双字节存储字符方式,(虽然客户端变成utf8,但是转换回来还是以16gbk的,windows依然是16gbk。)

所以这6字节对应了zhs16gbk字符集的3个字符,也就是我们看到的"涓浗"。






导入导出 exp   imp 客户端对字符的影响实验

 

 


创建两个库

test1 源数据库 字符集-----------   SIMPLIFIED CHINESE_CHINA.AL32UTF8     


test2 目标数据库 字符集-----------   SIMPLIFIED CHINESE_CHINA.16gbk


创建用户jiang/oracle  建立test表




oracle@linux5:/oracle>export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK" ###########环境变量


SQL>  select col1,dump(col2,1016) from test;


      COL1

----------

DUMP(COL2,1016)

--------------------------------------------------------------------------------

         2

Typ=1 Len=4 CharacterSet=AL32UTF8: d6,d0,b9,fa


         1

Typ=1 Len=6 CharacterSet=AL32UTF8: e4,b8,ad,e5,9b,bd




Export: Release 11.2.0.4.0 - Production on 星期一 11月 28 17:05:50 2016


Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.



连接到: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options

已导出 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集

服务器使用 AL32UTF8 字符集 (可能的字符集转换)

. 正在导出 pre-schema 过程对象和操作

. 正在导出用户 JIANG 的外部函数库名

. 导出 PUBLIC 类型同义词

. 正在导出专用类型同义词

. 正在导出用户 JIANG 的对象类型定义

即将导出 JIANG 的对象...

. 正在导出数据库链接

. 正在导出序号

. 正在导出簇定义

. 即将导出 JIANG 的表通过常规路径...

. . 正在导出表                            TEST导出了           2 行

. 正在导出同义词

. 正在导出视图

. 正在导出存储过程

. 正在导出运算符

. 正在导出引用完整性约束条件

. 正在导出触发器

. 正在导出索引类型

. 正在导出位图, 功能性索引和可扩展索引

. 正在导出后期表活动

. 正在导出实体化视图

. 正在导出快照日志

. 正在导出作业队列

. 正在导出刷新组和子组

. 正在导出维

. 正在导出 post-schema 过程对象和操作

. 正在导出统计信息

成功终止导出, 没有出现警告。







导入到test2 ,目标数据库字符集为16gbk


oracle@linux5:/oracle>imp jiang/oracle@test2 fromuser=jiang touser=jiang file=/backup/test1.dmp log=/backup/testimp.log


Import: Release 11.2.0.4.0 - Production on 星期一 11月 28 17:28:32 2016


Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.



连接到: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options


经由常规路径由 EXPORT:V11.02.00 创建的导出文件

已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入

. . 正在导入表                          "TEST"导入了           2 行

成功终止导入, 没有出现警告。

oracle@linux5:/oracle>



SQL> select * from test;


      COL1 COL2

---------- ----------

         2 ???

         1 中国

         

 

 SQL>  select col1,dump(col2,1016) from test;


      COL1

----------

DUMP(COL2,1016)

--------------------------------------------------------------------------------

         2

Typ=1 Len=4 CharacterSet=ZHS16GBK: a3,bf,3f,3f        


         1

Typ=1 Len=4 CharacterSet=ZHS16GBK: d6,d0,b9,fa          ------------2个字节一个汉字, 16gbk编码存储 数据库做了数字编码转换工作。



SQL>         







参考   http://blog.csdn.net/wuweilong/article/details/39694531

源端数据库test1 (1)字符集为utf8 →EXP客户端(2)→IMP客户端(3)→目标数据库(4) test2字符集为16gbk,

数据在迁移过程中要经历如上的4个点,数据在流动过程中(如上的3个箭头)需要依次比较箭头两端的字符集,

如果相同则不转换,如果不同则进行转换。如果相邻的两个点之间设置的字符集均不相同,则需要转换3次。

最好的设置方式是,因为(1)(4)数据库的字符集是固定的,则设置客户端的字符集(2)(3)均与(1)相同,

这样最多只在(3)→(4)的过程中发生一次字符集的转换。但是前提是(4)的字符集必须是(1)的的字符集的超集。客户端字符集是通过环境变量NLS_LANG来设置。




写入数据----字符转换过程


数据库端通过简单的判断跟 客户端环境变量的字符集  是否一致进行字符转换   一致则不转换,直接存储到数据库中,不一致则字符转换。

客户端的字符集的作用就是告知数据库端传输的字符编码


数据库看到客户端的字符集和数据库的字符集一致,此时oracle将不会再对字符作转换,因为它认为两边的字符编码是一致的。而此时,

我们欺骗了数据库,尽管我们将客户端字符集设置为和数据库一致,但是其实我们使用的windows7是zhs16gbk字符集编码(因为此时windows使用的就是这个字符编码),

对于字符"中国",zhs16gbk字符集里对应的编码为d6,d0,b9,fa。此时,oracle不加理会的直接将这个编码保存到了数据库中。




查找数据----字符转换过程(win7  16gbk一定)


当session 1开始查询时,oracle从表中取出这两个字符,并按照字符集al32utf8和字符集zhs16gbk的编码映射表,将它的转换成zhs16gbk字符编码,对于编码“e4,b8,ad,e5,9b,bd”,

它对应的zhs16gbk的字符编码为"d6,d0,b9,fa",这个编码对应的字符为”中国“,所以我们看到了这个字符正常显示出来了,3---2


而对于字符集存储的al32utf8字符编码“d6,d0,b9,fa”,

由于我们用于显示字符的windows环境使用的是zhs16gbk字符集,而在zhs16gbk字符集里面并没有对应这个编码的字符或者属于无法显示的符号,utf8---16gbk 转换找不到

于是使用了"?"这样的字符来替换,这就是为什么我们看到session 2输入的字符变成了这样的乱码。
























         

         

 

         

 

 

         



            

      






         

      

  

           


相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...