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