我用的數(shù)據(jù)庫是oracle11.2.0.4,數(shù)據(jù)庫字符集是al32utf8。
公司主營業(yè)務(wù):網(wǎng)站建設(shè)、網(wǎng)站制作、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)公司推出石嘴山免費(fèi)做網(wǎng)站回饋大家。
客戶端就是同一臺(tái)機(jī)器的windows 7
用window7的客戶端連接
查看windows客戶端中文字符
虛擬機(jī) 192.168.10.5 數(shù)據(jù)庫是test1 數(shù)據(jù)庫字符集是al32utf8。
C:\Users\Administrator>echo %NLS_LANG% -------查看客戶端字符命令
SIMPLIFIED CHINESE_CHINA.AL32UTF8
set NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK -----設(shè)置客戶端字符命令
數(shù)據(jù)庫是test1 ,數(shù)據(jù)庫字符集是al32utf8。
--session 1 設(shè)置客戶端字符集為 zhs16gbk(修改注冊(cè)表nls_lang項(xiàng)的characterset 為zhs16gbk) 向表中插入兩個(gè)中文字符。
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的標(biāo)記
1 row created.
SQL> commit;
Commit complete.
SQL> create table test(col1 number(1),col2 varchar2(10));
表已創(chuàng)建。
SQL> insert into test values(1,'中國');
已創(chuàng)建 1 行。
SQL>
-session 2 設(shè)置客戶端字符集 al32utf8(修改注冊(cè)表nls_lang項(xiàng)的characterset 為al32utf8),與數(shù)據(jù)庫字符集相同。 向表中插入兩個(gè)和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的標(biāo)記
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的結(jié)果中可以看到,相同的字符(注意,我指的是我們看到的,顯示為相同的字符 中國),在不同的字符集輸入環(huán)境(客戶端環(huán)境變量)下,顯示成了亂碼。
在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 涓浗 -----三個(gè)字符
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
不同的客戶端輸入的中文字符,在數(shù)據(jù)庫中存儲(chǔ)的字符編碼不一致。
session 1 輸入的字符"中國" 在數(shù)據(jù)庫中存儲(chǔ)的字符編碼為”e4,b8,ad,e5,9b,bd".
session 2 輸入的字符"中國" 在數(shù)據(jù)庫中存儲(chǔ)的字符編碼為”d6,d0,b9,fa".
會(huì)話一、
中國-------e4,b8,ad,e5,9b,bd 數(shù)據(jù)庫發(fā)現(xiàn)客戶端16gbk跟數(shù)據(jù)庫端的utf8字符不一致 做了字符轉(zhuǎn)換 首先將客戶端 中國 16gbk的(雙字節(jié))編碼轉(zhuǎn)成utf8(三字節(jié)編碼) 然后存儲(chǔ)下來。
會(huì)話二、
中國-------d6,d0,b9,fa 數(shù)據(jù)庫發(fā)現(xiàn)客戶端utf8跟數(shù)據(jù)庫端的utf8字符一致 欺騙了數(shù)據(jù)庫端,不做字符轉(zhuǎn)換,直接以16gbk(雙字節(jié))的字符編碼存儲(chǔ)到數(shù)據(jù)庫(utf8數(shù)據(jù)庫編碼為三字節(jié))中。
session 1 輸入的字符"中國" 在數(shù)據(jù)庫中存儲(chǔ)的字符編碼為”e4,b8,ad,e5,9b,bd"
session 2 輸入的字符"中國" 在數(shù)據(jù)庫中存儲(chǔ)的字符編碼為”d6,d0,b9,fa"
數(shù)據(jù)庫看到客戶端的字符集和數(shù)據(jù)庫的字符集一致,此時(shí)oracle將不會(huì)再對(duì)字符作轉(zhuǎn)換,因?yàn)樗J(rèn)為兩邊的字符編碼是一致的。而此時(shí),
我們欺騙了數(shù)據(jù)庫,盡管我們將客戶端字符集設(shè)置為和數(shù)據(jù)庫一致,但是其實(shí)我們使用的是zhs16gbk字符集編碼(因?yàn)榇藭r(shí)windows使用的就是這個(gè)字符編碼),
對(duì)于字符"中國",zhs16gbk字符集里對(duì)應(yīng)的編碼為d6,d0,b9,fa。此時(shí),oracle不加理會(huì)的直接將這個(gè)編碼保存到了數(shù)據(jù)庫中。
客戶端的字符集的作用就是告知數(shù)據(jù)庫端傳輸?shù)淖址幋a,跟數(shù)據(jù)庫端的字符集一致就直接存儲(chǔ),不一致就字符轉(zhuǎn)換。
查詢是存儲(chǔ)的字符轉(zhuǎn)換的逆過程。
session1查詢
SQL> select * from test;
COL1 COL2
---------- --------------------
1 中國
2 ???
當(dāng)session 1開始查詢時(shí),oracle從表中取出這兩個(gè)字符,并按照字符集al32utf8和字符集zhs16gbk的編碼映射表,將它的轉(zhuǎn)換成zhs16gbk字符編碼,對(duì)于編碼“e4,b8,ad,e5,9b,bd”,
它對(duì)應(yīng)的zhs16gbk的字符編碼為"d6,d0,b9,fa",這個(gè)編碼對(duì)應(yīng)的字符為”中國“,所以我們看到了這個(gè)字符正常顯示出來了,
而對(duì)于字符集存儲(chǔ)的al32utf8字符編碼“d6,d0,b9,fa”,
由于我們用于顯示字符的windows環(huán)境使用的是zhs16gbk字符集,而在zhs16gbk字符集里面并沒有對(duì)應(yīng)這個(gè)編碼的字符或者屬于無法顯示的符號(hào),utf8---16gbk 轉(zhuǎn)換找不到
于是使用了"?"這樣的字符來替換,這就是為什么我們看到session 2輸入的字符變成了這樣的亂碼。
session2查詢
SQL> select * from test;
COL1 COL2
---------- ----------
1 涓浗
2 中國
SQL>
當(dāng)session 2開始查詢時(shí),oracle從表中取出這兩個(gè)字符,由于客戶端(nls_lang)和數(shù)據(jù)庫的字符集設(shè)置一致,oracle將忽略字符的轉(zhuǎn)換問題,
于是直接將數(shù)據(jù)庫中存儲(chǔ)的字符返回給客戶端。對(duì)于編碼為"d6,d0,b9,fa"的字符,返回給客戶端,而客戶端顯示所用的字符集正好是zhs16gbk,在這個(gè)字符集里,########(雖然客戶端變成ut8,但是轉(zhuǎn)換回來還是以16gbk的,windows依然是16gbk。)
這個(gè)編碼對(duì)應(yīng)的是"中國"兩個(gè)字符,所以就正常顯示出來了。
對(duì)于字符編碼“e4,b8,ad,e5,9b,bd”,返回到客戶端後,因?yàn)樵趜hs16gbk里采用的是雙字節(jié)存儲(chǔ)字符方式,(雖然客戶端變成utf8,但是轉(zhuǎn)換回來還是以16gbk的,windows依然是16gbk。)
所以這6字節(jié)對(duì)應(yīng)了zhs16gbk字符集的3個(gè)字符,也就是我們看到的"涓浗"。
導(dǎo)入導(dǎo)出 exp imp 客戶端對(duì)字符的影響實(shí)驗(yàn)
創(chuàng)建兩個(gè)庫
test1 源數(shù)據(jù)庫 字符集----------- SIMPLIFIED CHINESE_CHINA.AL32UTF8
test2 目標(biāo)數(shù)據(jù)庫 字符集----------- SIMPLIFIED CHINESE_CHINA.16gbk
創(chuàng)建用戶jiang/oracle 建立test表
oracle@linux5:/oracle>export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK" ###########環(huán)境變量
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
已導(dǎo)出 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集
服務(wù)器使用 AL32UTF8 字符集 (可能的字符集轉(zhuǎn)換)
. 正在導(dǎo)出 pre-schema 過程對(duì)象和操作
. 正在導(dǎo)出用戶 JIANG 的外部函數(shù)庫名
. 導(dǎo)出 PUBLIC 類型同義詞
. 正在導(dǎo)出專用類型同義詞
. 正在導(dǎo)出用戶 JIANG 的對(duì)象類型定義
即將導(dǎo)出 JIANG 的對(duì)象...
. 正在導(dǎo)出數(shù)據(jù)庫鏈接
. 正在導(dǎo)出序號(hào)
. 正在導(dǎo)出簇定義
. 即將導(dǎo)出 JIANG 的表通過常規(guī)路徑...
. . 正在導(dǎo)出表 TEST導(dǎo)出了 2 行
. 正在導(dǎo)出同義詞
. 正在導(dǎo)出視圖
. 正在導(dǎo)出存儲(chǔ)過程
. 正在導(dǎo)出運(yùn)算符
. 正在導(dǎo)出引用完整性約束條件
. 正在導(dǎo)出觸發(fā)器
. 正在導(dǎo)出索引類型
. 正在導(dǎo)出位圖, 功能性索引和可擴(kuò)展索引
. 正在導(dǎo)出后期表活動(dòng)
. 正在導(dǎo)出實(shí)體化視圖
. 正在導(dǎo)出快照日志
. 正在導(dǎo)出作業(yè)隊(duì)列
. 正在導(dǎo)出刷新組和子組
. 正在導(dǎo)出維
. 正在導(dǎo)出 post-schema 過程對(duì)象和操作
. 正在導(dǎo)出統(tǒng)計(jì)信息
成功終止導(dǎo)出, 沒有出現(xiàn)警告。
導(dǎo)入到test2 ,目標(biāo)數(shù)據(jù)庫字符集為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
經(jīng)由常規(guī)路徑由 EXPORT:V11.02.00 創(chuàng)建的導(dǎo)出文件
已經(jīng)完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的導(dǎo)入
. . 正在導(dǎo)入表 "TEST"導(dǎo)入了 2 行
成功終止導(dǎo)入, 沒有出現(xiàn)警告。
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個(gè)字節(jié)一個(gè)漢字, 16gbk編碼存儲(chǔ) 數(shù)據(jù)庫做了數(shù)字編碼轉(zhuǎn)換工作。
SQL>
參考 http://blog.csdn.net/wuweilong/article/details/39694531
源端數(shù)據(jù)庫test1 (1)字符集為utf8 →EXP客戶端(2)→IMP客戶端(3)→目標(biāo)數(shù)據(jù)庫(4) test2字符集為16gbk,
數(shù)據(jù)在遷移過程中要經(jīng)歷如上的4個(gè)點(diǎn),數(shù)據(jù)在流動(dòng)過程中(如上的3個(gè)箭頭)需要依次比較箭頭兩端的字符集,
如果相同則不轉(zhuǎn)換,如果不同則進(jìn)行轉(zhuǎn)換。如果相鄰的兩個(gè)點(diǎn)之間設(shè)置的字符集均不相同,則需要轉(zhuǎn)換3次。
最好的設(shè)置方式是,因?yàn)椋?)(4)數(shù)據(jù)庫的字符集是固定的,則設(shè)置客戶端的字符集(2)(3)均與(1)相同,
這樣最多只在(3)→(4)的過程中發(fā)生一次字符集的轉(zhuǎn)換。但是前提是(4)的字符集必須是(1)的的字符集的超集??蛻舳俗址峭ㄟ^環(huán)境變量NLS_LANG來設(shè)置。
寫入數(shù)據(jù)----字符轉(zhuǎn)換過程
數(shù)據(jù)庫端通過簡單的判斷跟 客戶端環(huán)境變量的字符集 是否一致進(jìn)行字符轉(zhuǎn)換 一致則不轉(zhuǎn)換,直接存儲(chǔ)到數(shù)據(jù)庫中,不一致則字符轉(zhuǎn)換。
客戶端的字符集的作用就是告知數(shù)據(jù)庫端傳輸?shù)淖址幋a
數(shù)據(jù)庫看到客戶端的字符集和數(shù)據(jù)庫的字符集一致,此時(shí)oracle將不會(huì)再對(duì)字符作轉(zhuǎn)換,因?yàn)樗J(rèn)為兩邊的字符編碼是一致的。而此時(shí),
我們欺騙了數(shù)據(jù)庫,盡管我們將客戶端字符集設(shè)置為和數(shù)據(jù)庫一致,但是其實(shí)我們使用的windows7是zhs16gbk字符集編碼(因?yàn)榇藭r(shí)windows使用的就是這個(gè)字符編碼),
對(duì)于字符"中國",zhs16gbk字符集里對(duì)應(yīng)的編碼為d6,d0,b9,fa。此時(shí),oracle不加理會(huì)的直接將這個(gè)編碼保存到了數(shù)據(jù)庫中。
查找數(shù)據(jù)----字符轉(zhuǎn)換過程(win7 16gbk一定)
當(dāng)session 1開始查詢時(shí),oracle從表中取出這兩個(gè)字符,并按照字符集al32utf8和字符集zhs16gbk的編碼映射表,將它的轉(zhuǎn)換成zhs16gbk字符編碼,對(duì)于編碼“e4,b8,ad,e5,9b,bd”,
它對(duì)應(yīng)的zhs16gbk的字符編碼為"d6,d0,b9,fa",這個(gè)編碼對(duì)應(yīng)的字符為”中國“,所以我們看到了這個(gè)字符正常顯示出來了,3---2
而對(duì)于字符集存儲(chǔ)的al32utf8字符編碼“d6,d0,b9,fa”,
由于我們用于顯示字符的windows環(huán)境使用的是zhs16gbk字符集,而在zhs16gbk字符集里面并沒有對(duì)應(yīng)這個(gè)編碼的字符或者屬于無法顯示的符號(hào),utf8---16gbk 轉(zhuǎn)換找不到
于是使用了"?"這樣的字符來替換,這就是為什么我們看到session 2輸入的字符變成了這樣的亂碼。