Oracle中dmp導入/導出、數據庫操作等過程中的字符集問題

描述:本文主要記錄了Oracle數據庫的字符集問題,也涉及作爲服務器操作系統的UNIX/LINUX、CentOS或者Windows的字符集與Oracle字符集之間的關聯關係。

Oracle數據庫的字符集問題不算是大問題,但也是一個頭疼的問題。這是因爲有這麼三個原因:一是Oracle數據庫在安裝時指定好字符集之後一般不能更改,二是字符集問題涉及服務器與客戶端之間的存取問題,三是Oracle數據庫遷移時也會跟字符集非常相關。

如果要說清楚Oracle字符集的相關問題,則要先理清數據庫運行過程中的架構以及在這個架構中的字符集設置及這些設置之間的關聯關係。

如圖:

在這個圖中,爲了說明問題,我們將服務器與客戶端分開,客戶端用應用程序比如sqlplus或者PL/SQL與服務端相連。

服務端有兩個字符集:服務端操作系統字符集(4)、服務端數據庫字符集(1);

客戶端有一個字符集:客戶端操作系統字符集(2);

客戶端有一個參數:操作系統參數NLS_LANG(3)。
    LINUX系統查詢命令:
    echo $LANG
    echo $NLS_LANG
    oracle數據庫查詢命令:
    select userenv('language') from dual;

這三個字符集與一個參數中,有一個字符集對整個架構的運行沒有影響,它就是服務端操作系統字符集(4),所以這個字符集將不再出現在我們的討論過程中。

爲什麼這個服務端操作系統字符集沒有用呢?這是因爲Oracle在存取字符時與客戶端進行字符集確認與轉碼的過程是由Oracle數據庫自身完成的,不需要經過Oracle數據庫所在的服務器的幫助。具體的是怎麼回事用以下例子說明一下。

比如在Oracle數據庫中有一個表,用如下語句創建:

create table test(name varchar2(10));

爲了說明問題假定有這樣的一個環境:服務器端Oracle數據庫的字符集是UTF8,客戶端操作系統字符集是ZHS16GBK,客戶端NLS_LANG參數設置爲ZHS16GBK。

那麼從客戶端應用程序(比如sqlplus)發出這樣一條命令:

insert into test (name) values('中國');

首先,這裏有一個字符串“中國”,客戶端操作系統用ZHS16GBK對它進行編碼,比如編成“167219”,並把它交給sqlplus程序,然後把它發送給Oracle數據庫。

其次,Oracle數據庫收到一串編碼“167219”,不是直接往數據庫裏一扔就完事的,它要問客戶端操作系統:“請問你給我的這串代碼是用什麼格式編碼的啊?”客戶端操作系統怎麼回答?它會這麼回答:“編碼格式請參照參數NLS_LANG”。Oracle數據庫一看,NLS_LANG='ZHS16GBK',這個編碼格式與Oracle數據庫自身的編碼格式“UTF8”不一樣,然後就是Oracle數據庫發揮自己專長的地方了,爲什麼呢?因爲Oracle數據庫有它自己的編碼表,而且不是一張而是好多張編碼表,它可以根據編碼表對編碼進行翻譯和轉碼。這就好比Oracle數據庫是一個翻譯,它會好幾國語言,牛人一個。像上面的這個情況,Oracle會把“167219”這串代碼拿過來,根據參數NLS_LANG查ZHS16GBK編碼表,找到對應這串代碼的字符“中國”,然後再到UTF8編碼表中查“中國”對應的編碼,比如查到的結果是“3224678”。

最後,將轉碼之後的編碼“3224678”存放到Oracle數據庫中去。

爲了進一步說明問題,我們再執行一條語句:

select name from test;

首先,Oracle數據庫會從數據庫中取出一串代碼“3224678”。

其次,Oracle數據庫不是直接把這串代碼交給sqlplus程序,它會多問一句:“代碼串我是取出來了,它是UTF8編碼格式的,請問sqlplus,你希望要什麼編碼格式的?”,sqlplus仍然會很爽快地告訴Oracle數據庫:“編碼格式請繼續參照參數NLS_LANG”。Oracle數據庫一看,ZHS16GBK跟UTF8又不一樣,所以先查UTF8編碼表,找到編碼“3224678”對應的字符“中國”,再查ZHS16GBK編碼表,找到“中國”對應的編碼“167219”,然後就是把最後得到的這串編碼“167219”交給sqlplus程序。

最後,sqlplus直接把得到的這串編碼扔給客戶端操作系統,而操作系統只有ZHS16GBK編碼表,它不會問得到的這串編碼是什麼格式的,只會直接到ZHS16GBK編碼表中去查“167219”對應的字符是什麼,並把它交給應用程序顯示出來。這個顯示的結果是“中國”。

以上就是一個完整的從客戶端編碼並經過Oracle數據庫轉碼存入數據庫,然後從數據庫取出並轉碼交給客戶端顯示的實驗。

從以上過程我們可以得出以下一些結論:

1.對Oracle數據庫存取起作用的是這些:客戶端操作系統字符集、客戶端操作系統參數NLS_LANG、服務端數據庫字符集。

2.對Oracle數據庫不起作用的是服務端操作系統字符集。

3.客戶端操作系統只有一張編碼表,與客戶端字符集對應。

4.Oracle數據庫的字符集只有一個,並且固定,一般不改變。

5.存放在Oracle數據庫中的字符串的編碼格式只有一個,它就是數據庫的字符集所對應的編碼格式。

6.Oracle數據庫有很多張編碼表,可以在數據存入時將其它編碼格式的編碼轉換爲數據庫字符集指定的格式,取出時從數據庫字符集指定的格式轉換爲其它編碼格式。

7.整個架構中的轉碼只發生在Oracle數據庫邊界上,其它地方沒有。

8.Oracle是根據客戶端操作系統的參數NLS_LANG與自己的字符集進行對照來確定是否需要進行轉碼的。

最最重要的結論出來了:

9.Oracle數據庫如何選擇字符集?只有一個原則,那就是這個字符集要包含數據庫運行過程中所能存入的數據字符,通常作爲中國人我們選擇ZHS16GBK,如果想再保險一點,選擇AL32UTF8。

10.服務器操作系統選擇什麼字符集?這個字符集與數據庫字符集一點關係都沒有,只跟誰有關?操作系統管理員!所以它的選擇原則是,系統管理員想選擇什麼就選擇什麼。

11.客戶端操作系統選擇什麼字符集?我是中國人,我用中文操作系統,所以我選擇ZHS16GBK。建議中國人都選擇ZHS16GBK。

12.客戶端操作系統參數NLS_LANG參數如何設置?這個只有一個設置方法,那就是與操作系統字符集相同。要不然會出問題的……

注:最好的,最不容易出字符集錯誤的就是:將數據庫字符集、客戶端字符集、客戶端操作系統NLS_LANG參數三個地方作同樣的設置。

另外再記錄一下EXP和IMP過程與字符集相關的事情。

EXP時,起作用的有Oracle數據庫的字符集和客戶端操作系統參數NLS_LANG兩項,這時服務器與客戶端操作系統字符集都不起作用。如果客戶端操作系統參數NLS_LANG與Oracle數據庫的字符集相同,那就直接導出,不需要轉碼,並且導出文件的字符集與上述兩項一樣;如果客戶端操作系統參數NLS_LANG與Oracle數據庫的字符集不同,那麼導出時Oracle數據庫會將數據文件從Oracle數據庫的字符集編碼格式轉碼成客戶端操作系統參數NLS_LANG指定的編碼格式。總而言之一句話:導出文件的字符集格式與導出客戶端操作系統參數NLS_LANG一定相同。

IMP時,起作用的仍然是兩項,一項是DMP文件第二第三字節指定的字符集,另外一項是Oracle數據庫的字符集。兩個相同就不需要轉碼,兩個不同就轉成Oracle數據庫字符集指定的編碼格式。

最後記錄我遇到的幾個問題。

1.我前段時間測試過在CentOS上安裝Oracle11gR2,那時我設置過CentOS的字符集中“zh_CN.UTF-8”,並且安裝中文字體,當時也確實能得到我想要的結果,那就是:我安裝的Oracle數據庫的字符集是中文字符集ZHS16GBK。爲什麼呢,因爲Oracle數據庫的字符集是默認地根據操作系統的字符集來的,並且我也就選擇它的默認字符集。所以沒有出錯。

但是,但是,現在我知道了,這個作爲服務器的CentOS的字符集對Oracle數據庫沒有影響,所以現在讓我再來一回去選擇它是什麼字符集,我會選擇en_US.UTF-8,甚至en_US.US7ASCII。爲什麼呢,因爲在shell界面顯示中文確認是一個難題,所以管理CentOS,還是用英文吧,比較方便又對數據庫沒影響。隨它去吧。

2.英文操作系統安裝中文字符集oracle數據庫時,一定要注意在選擇數據庫字符集的時候慢一點,細心地選擇一個ZHS16GBK或者AL32UTF8。

3.DMP文件是US7ASCII字符集,要把它導入字符集是ZHS16GBK的數據庫中去,如何操作?第一步:安裝一個US7ASCII字符集的數據庫(比如說9i);第二步,將DMP文件導入該數據庫;第三步,設置導出客戶端操作系統參數NLS_LANG=ZHS16GBK,然後導出;第四步,將後導出的DMP文件導入字符集是ZHS16GBK的數據庫中去。理論上成功。需要做實驗測試。

4.曾經說到,一般情況下數據庫的字符集在數據庫安裝好之後就不可以更改。那麼如果一定要改,怎麼辦?比如說原來的字符集是ZHS16GBK,非要讓轉成UTF8,有沒有辦法?答案是有的,但是,但是不一定會全部成功,這裏有一個嚴格超集的概念,這個概念在這篇文章裏不講。答案是這麼做,設置導出客戶端操作系統參數爲UTF8,然後導出,這裏,數據編碼格式會從ZHS16GBK轉碼成UTF8,然後再刪除ZHS16GBK的數據庫,新建一個UTF8的數據庫,再導入就可以了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章