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