張孌
1.問題提出背景
隨著信息化建設(shè)的不斷深入,各大港口公司都運用應(yīng)用系統(tǒng)來輔助生產(chǎn)和管理,數(shù)據(jù)庫是其中不可或缺的部分,占有重要的地位。在各大數(shù)據(jù)庫產(chǎn)品中,選擇 ORACLE 作為數(shù)據(jù)庫管理平臺的用戶比較多。 ORACLE 不論是數(shù)據(jù)庫管理能力還是安全性都是無可非議的,但是,它在漢字信息的顯示方面確實給我們帶來不少麻煩,筆者就經(jīng)常遇到有關(guān)數(shù)據(jù)庫漢字顯示的問題,尤其是在數(shù)據(jù)庫導(dǎo)入導(dǎo)出的時候,主要現(xiàn)象是把漢字顯示為不可識別的亂碼(一般是“?”),造成原來大量信息無法使用。本文將就這一問題產(chǎn)生的原因和解決辦法進行一些探討。
2.ORACLE字符集概述
2.1 字符集定義
字符集是一個字節(jié)數(shù)據(jù)的解釋的符號集合,有大小之分有相互的包括關(guān)系,如US7ASCII就是ZHS16GBK的子集,從US7ASCII到ZHS16GBK不會有數(shù)據(jù)解釋上的問題,不會有數(shù)據(jù)丟失,Oracle對這種問題也要求從子集到超集的導(dǎo)出受支持,反之不行。字符集決定數(shù)據(jù)庫所支持的語言標準,也就是說,數(shù)據(jù)庫支持中文、日文或是英文不是有操作系統(tǒng)平臺決定的,而是由字符集決定的。
字符集不僅需在服務(wù)器端存在,而且客戶端也必須有字符集注冊。服務(wù)器端字符集是在安裝數(shù)據(jù)庫時指定的,字符集登記信息存儲在數(shù)據(jù)庫字典的 V$NLS_PARAMETERS 表中;客戶端字符集是在系統(tǒng)注冊表中登記的。要在客戶端正確顯示數(shù)據(jù)庫漢字信息,首先必須使服務(wù)器端的字符集與客戶端的字符集一致;其次是加載到數(shù)據(jù)庫的數(shù)據(jù)字符集必須與服務(wù)器端字符集一致。影響數(shù)據(jù)庫字符集最重要的參數(shù)是NLS_LANG參數(shù)。它的格式如下:NLS_LANG = language_territory.charset。它有三個組成部分(語言、地域和字符集),每個成分控制了NLS子集的特性。其中: Language 指定服務(wù)器消息的語言,也就是sqlplus的程序的顯示字體,一般常用SIMPLIFIED CHINESE,American America;Territory 指定服務(wù)器的日期和數(shù)字格式;Charset是字符集的設(shè)定。常用的一些字符集有UTF8,US7ASCII,ZHS16GBK,AL32UTF8。
從NLS_LANG的組成我們可以看出,真正影響數(shù)據(jù)庫字符集的其實是第三部分。所以兩個數(shù)據(jù)庫之間的字符集只要第三部分一樣就可以相互導(dǎo)入導(dǎo)出數(shù)據(jù),前面影響的只是提示信息是中文還是英文。
2.2oracle字符集的查詢方法
2.2.1查詢oracle服務(wù)器端的字符集 SQL> select * from nls_database_parameters;
2.2.2查詢dmp文件的字符集 用Oracle的exp工具導(dǎo)出的dmp文件也包含了字符集信息,dmp文件的第2和第3個字節(jié)記錄了它的字符集。如果文件不大,比如只有幾M或幾十M,可以用UltraEdit打開(16進制方式),看第2、第3個字節(jié)的內(nèi)容,如0001,然后用以下SQL查出它對應(yīng)的字符集:SQL> select nls_charset_name(to_number('0001','xxxx')) from dual;如果文件很大,比如有2G以上(這也是最常見的情況),用文本編輯器打開很慢或者完全打不開,可以用以下命令(在unix主機上):$ cat a.dmp |od -x| head 其中,a.dmp是需要查看字符集的dmp文件。
2.2.3查詢Oracle Client端的字符集
在Windows中,決定客戶端字符集的參數(shù)nls_lang定義在Windows系統(tǒng)的注冊表里,如果要重新定義,可以直接修改注冊表。運行注冊表,選擇” HKEY_LACAL_MACHINE”→”SOFTWARE”→”O(jiān)RACLE”→”HOME0”,查看里面的NLS_LANG數(shù)據(jù)項。還可以在Dos窗口里面自己設(shè)置,比如:set nls_lang=AMERICAN_AMERICA. US7ASCII 這樣就只影響這個窗口里面的環(huán)境變量。
3.幾種亂碼問題的解決方法
3.1服務(wù)器端字符集與客戶字端字符集不同,但與加載數(shù)據(jù)字符集一致。
解決方法:設(shè)置客戶端字符集與服務(wù)器端字符集一致。首先查看服務(wù)器端字符集,然后按照服務(wù)器端字符集對客戶端進行配置。修改注冊表信息,將NLS_LANG數(shù)據(jù)項值改為與服務(wù)器端相同的字符集。
3.2服務(wù)器端字符集與客戶端字符集相同,與加載數(shù)據(jù)字符集不一致。
這類問題一般發(fā)生在服務(wù)器數(shù)據(jù)庫版本升級或重新安裝系統(tǒng)時選擇了與原來服務(wù)器端不同的字符集,而恢復(fù)加載的備份數(shù)據(jù)仍是按原字符集導(dǎo)出,或者加載從其它使用不同字符集的數(shù)據(jù)庫導(dǎo)出數(shù)據(jù)的情況。這兩種情況中,不管服務(wù)器端和客戶端字符集是否一致都無法正常顯示漢字。解決方法:強制將加載數(shù)據(jù)的字符集改為與服務(wù)器端字符集一致。
方法一:強行修改服務(wù)器端數(shù)據(jù)庫當前字符集。在用Imp命令加載數(shù)據(jù)前,先在客戶端用sql*plus以DBA 用戶登錄,執(zhí)行 SQL > create database character set US7ASCII ;你會發(fā)現(xiàn)語句執(zhí)行過程中,會出現(xiàn)錯誤提示信息,此時不用理會,實際上數(shù)據(jù)庫的字符集已被強行修改為US7ASCII,接著用imp命令裝載數(shù)據(jù)。等數(shù)據(jù)裝載完成以后,關(guān)閉數(shù)據(jù)庫,再啟動數(shù)據(jù)庫,用合法用戶登錄數(shù)據(jù)庫,在 sql> 命令提示符下,查詢數(shù)據(jù)庫字符集,可以看到其已復(fù)原,這時再查看有漢字字符數(shù)據(jù)的表時,漢字已能被正確顯示。
方法二:利用數(shù)據(jù)格式轉(zhuǎn)儲,避開字符集限制。這種方法主要用于加載外來數(shù)據(jù)庫的不同字符集數(shù)據(jù)。其方法如下:先將數(shù)據(jù)加載到具有相同字符集的服務(wù)器上,然后用轉(zhuǎn)換工具卸出為access格式數(shù)據(jù)庫,再用轉(zhuǎn)換工具轉(zhuǎn)入到不同字符集的數(shù)據(jù)庫中,這樣就避免了字符集的困擾。
3.3服務(wù)器端字符集與客戶端字符集不同,與輸入數(shù)據(jù)字符集不一致。
這種情況是在客戶端與服務(wù)器端字符集不一致時,從客戶端輸入了漢字信息。輸入的這些信息即便是把客戶端字符集更改正確,也無法顯示漢字。對于這種情況,沒有很好的辦法,只能先把客戶端與服務(wù)器端字符集匹配一致后,重新錄入數(shù)據(jù)。
通過上面的了解,我們知道導(dǎo)致在后期使用數(shù)據(jù)庫是出現(xiàn)種種關(guān)于字符集的問題,多半是由于在數(shù)據(jù)庫設(shè)計、安裝指出沒有很好地考慮到以后的需要,所以,我們完全可以通過在服務(wù)器和客戶端使用相同的字符集來避免由此類問題引出的麻煩。
4.應(yīng)注意的問題
一旦數(shù)據(jù)庫創(chuàng)建后,數(shù)據(jù)庫的字符集理論上講是不能改變的。因此,在設(shè)計和安裝之初考慮使用哪一種字符集十分重要。根據(jù)Oracle的官方說明,字符集的轉(zhuǎn)換是從子集到超集受支持,反之不行。如果兩種字符集之間根本沒有子集和超集的關(guān)系,那么字符集的轉(zhuǎn)換是不受支持的。對數(shù)據(jù)庫而言,錯誤的修改字符集將會導(dǎo)致很多不可測的后果,可能會嚴重影響數(shù)據(jù)庫的正常運行,所以在修改之前一定要確認兩種字符集是否存在子集和超集的關(guān)系。一般來說,除非萬不得已,我們不建議修改數(shù)據(jù)庫服務(wù)器端的字符集。在10g數(shù)據(jù)庫中,客戶端字符集必須與數(shù)據(jù)庫和行字符集類型一致,否則漢字將出現(xiàn)亂碼;如果要將早期數(shù)據(jù)庫中的數(shù)據(jù)移入到9i、10g中,由于原始數(shù)據(jù)字符集問題,新的數(shù)據(jù)庫核心必須使用早期數(shù)據(jù)庫核心字符集類型,客戶端也要保持與早期核心字符集一致。