國內最常用的Oracle字元集ZHS16GBK(GBK 16-bit Simplified Chinese)能夠支援繁體中文,並且按照2個字元長度儲存一個漢字。UTF8字元集是多位元組儲存,1個漢字(簡體、繁體)有時採用3個字元長度儲存。
Oracle支援字元集的更改,但是UTF8是Oracle中最大的字元集,也就是說UTF8是ZHS16GBK的嚴格超集。
對於子集到超集的轉換,Oracle是允許的,但是對於超集到子集的轉換是不允許的。一般對於超集到子集的轉換,建議是通過dbca刪除原來的資料庫,重新再建庫,選擇正確的字元集,然後匯入備份。
我的方案是:先備份資料,然後強制轉換字元集從UTF8到ZHS16GBK,然後匯入備份資料。如果不行,才來重建立庫,設定字元集ZHS16GBK,匯入備份資料。如果這還不行,就把更改字元集從ZHS16GBK到UTF8(這是安全的),再匯入備份資料,恢複到原始狀況。這樣就有可能避開重建立庫的麻煩。
1. 備份資料庫中所有使用者的資料
以oracle使用者登陸,執行以下命令
# export NLS_LANG = “SIMPLIFIED CHINESE_CHINA.UTF8”
保持與資料庫伺服器端一致,這樣在exp匯出時,就不會存在字元的轉換了,備份最原始的資料。
2. 評估UTF8轉換成ZHS16GBK的風險
轉換之前,要使用Oracle的csscan工具對資料庫掃描,評估字元集轉換前後,資料有可能的損壞情況。如果評估情況糟糕,那就絕對要放棄了。
先安裝屬於 CSMIG 使用者的一套表和過程。以oracle使用者登陸UNIX,
#sqlplus “/ as sysdab”
SQL>@$ORACLE_HOME/ rdbms/admin/csminst.sql
SQL>exit
# $ORACLE_HOME\bin\csscan -help
可以更清楚如何使用csscan。
# $ORACLE_HOME/bin/csscan system/sunday user=mmsc FROMCHAR=UTF8 TOCHAR=ZHS16GBK ARRAY=102400 PROCESS=3 > csscan.log
以上命令意思是掃描使用者:mmsc中的所有資料,從字元集UTF8更改為ZHS16GBK的轉換情況。然後得到三個檔案:scan.txt、scan.out、scan.err。
查看scan.out,scan.err,可以看出mmsc使用者下的所有的資料都是可以轉換的,並且沒有出現轉換“Exceptional”的情況,因此可以更放心一點。
3. 更改資料庫的字元集為ZHS16GBK
前面說過,通過命令“Alter Database Characeter Set XXXX”,實現從超集到子集的轉換,在Oracle是不允許的。但是該命令,提供這樣的命令方式:
Alter Database Character Set INTERNAL_CONVERT/ INTERNAL_USE XXXX
這是Oracle的非公開命令。“在使用這個命令時,Oracle會跳過所有子集及超集的檢查,在任一字元集之間進行強制轉換,所以,使用這個命令時你必須十分小心,你必須清楚這一操作會帶來的風險”。
以oracle使用者登陸UNIX,
#sqlplus “/ as sysdba”
SQL> SHUTDOWN IMMEDIATE;
SQL> STARTUP MOUNT;
SQL> ALTER SESSION SET SQL_TRACE=TRUE;
SQL> ALTER SYSTEM ENABLE RESTRICTED SESSION;
SQL> ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;
SQL> ALTER SYSTEM SET AQ_TM_PROCESSES=0;
SQL> ALTER DATABASE OPEN;
SQL> ALTER DATABASE CHARACTER SET ZHS16GBK;
//如果不使用“INTERNAL_USE”參數,系統會提示出錯:
//ERROR at line 1:
//ORA-12712: new character set must be a superset of old character set
SQL> ALTER SESSION SET SQL_TRACE=FALSE;
SQL> SHUTDOWN IMMEDIATE;
SQL> STARTUP;
此時,檢查一下資料庫的字元集是否更改過來
SQL> select value$ from props$ where name=’NLS_CHARACTERSET’;
VALUE$
-----------------
ZHS16GBK
緊接著檢查一下資料庫中簡體中文、繁體中文是否正常,不會出現亂碼。
SQL>select spid,spname,spshortname from spinfovisual_hk
…...
非常不幸,我看到了一堆亂碼,這也證明了Oracle不支援字元集從超集到子集的更改,當時心裡很緊張,很怕失敗,從而恢複到原樣。
但是根據以前的驗證,把UTF8下的備份匯入到ZHS16GBK中去,是OK的,所以繼續嘗試。
4. 匯入備份的使用者資料
還是以oracle使用者登陸UNIX, 先刪除庫中的使用者mmsc:
#sqlplus “/ as sysdba”
SQL>drop user mmsc cascade;
SQL>exit
再運行createuser.sql,產生mmsc使用者。
然後使用原來的備份檔案,匯入到mmsc使用者中:
注意:先設定NLS_LANG要與當前資料庫的一致:ZHS16GBK。這樣,匯出時使用者會話的NLS_LANG為UTF8,與原先的資料庫字元集一致;現在為ZHS16GBK,與此時的資料庫字元集一致。這樣,匯入時,就會進行字元轉換。
# export NLS_LANG = “SIMPLIFIED CHINESE_CHINA.ZHS16GBK”
#imp mmsc/mmsc@mdspdb file=DSMPD113_user_mmsc.dmp ignore=y fromuser=mmsc touser=mmsc
馬上查看資料庫中簡體、繁體中文,哈哈,沒有亂碼了,一切顯示正常。
緊接著進行驗證,也證明了:1個漢字此時只佔用2個字元長度。問題解決了!
國內最常用的Oracle字元集ZHS16GBK(GBK 16-bit Simplified Chinese)能夠支援繁體中文,並且按照2個字元長度儲存一個漢字。UTF8字元集是多位元組儲存,1個漢字(簡體、繁體)有時採用3個字元長度儲存。
Oracle支援字元集的更改,但是UTF8是Oracle中最大的字元集,也就是說UTF8是ZHS16GBK的嚴格超集。
對於子集到超集的轉換,Oracle是允許的,但是對於超集到子集的轉換是不允許的。一般對於超集到子集的轉換,建議是通過dbca刪除原來的資料庫,重新再建庫,選擇正確的字元集,然後匯入備份。
我的方案是:先備份資料,然後強制轉換字元集從UTF8到ZHS16GBK,然後匯入備份資料。如果不行,才來重建立庫,設定字元集ZHS16GBK,匯入備份資料。如果這還不行,就把更改字元集從ZHS16GBK到UTF8(這是安全的),再匯入備份資料,恢複到原始狀況。這樣就有可能避開重建立庫的麻煩。
1. 備份資料庫中所有使用者的資料
以oracle使用者登陸,執行以下命令
# export NLS_LANG = “SIMPLIFIED CHINESE_CHINA.UTF8”
保持與資料庫伺服器端一致,這樣在exp匯出時,就不會存在字元的轉換了,備份最原始的資料。
2. 評估UTF8轉換成ZHS16GBK的風險
轉換之前,要使用Oracle的csscan工具對資料庫掃描,評估字元集轉換前後,資料有可能的損壞情況。如果評估情況糟糕,那就絕對要放棄了。
先安裝屬於 CSMIG 使用者的一套表和過程。以oracle使用者登陸UNIX,
#sqlplus “/ as sysdab”
SQL>@$ORACLE_HOME/ rdbms/admin/csminst.sql
SQL>exit
# $ORACLE_HOME\bin\csscan -help
可以更清楚如何使用csscan。
# $ORACLE_HOME/bin/csscan system/sunday user=mmsc FROMCHAR=UTF8 TOCHAR=ZHS16GBK ARRAY=102400 PROCESS=3 > csscan.log
以上命令意思是掃描使用者:mmsc中的所有資料,從字元集UTF8更改為ZHS16GBK的轉換情況。然後得到三個檔案:scan.txt、scan.out、scan.err。
查看scan.out,scan.err,可以看出mmsc使用者下的所有的資料都是可以轉換的,並且沒有出現轉換“Exceptional”的情況,因此可以更放心一點。
3. 更改資料庫的字元集為ZHS16GBK
前面說過,通過命令“Alter Database Characeter Set XXXX”,實現從超集到子集的轉換,在Oracle是不允許的。但是該命令,提供這樣的命令方式:
Alter Database Character Set INTERNAL_CONVERT/ INTERNAL_USE XXXX
這是Oracle的非公開命令。“在使用這個命令時,Oracle會跳過所有子集及超集的檢查,在任一字元集之間進行強制轉換,所以,使用這個命令時你必須十分小心,你必須清楚這一操作會帶來的風險”。
以oracle使用者登陸UNIX,
#sqlplus “/ as sysdba”
SQL> SHUTDOWN IMMEDIATE;
SQL> STARTUP MOUNT;
SQL> ALTER SESSION SET SQL_TRACE=TRUE;
SQL> ALTER SYSTEM ENABLE RESTRICTED SESSION;
SQL> ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;
SQL> ALTER SYSTEM SET AQ_TM_PROCESSES=0;
SQL> ALTER DATABASE OPEN;
SQL> ALTER DATABASE CHARACTER SET ZHS16GBK;
//如果不使用“INTERNAL_USE”參數,系統會提示出錯:
//ERROR at line 1:
//ORA-12712: new character set must be a superset of old character set
SQL> ALTER SESSION SET SQL_TRACE=FALSE;
SQL> SHUTDOWN IMMEDIATE;
SQL> STARTUP;
此時,檢查一下資料庫的字元集是否更改過來
SQL> select value$ from props$ where name=’NLS_CHARACTERSET’;
VALUE$
-----------------
ZHS16GBK
緊接著檢查一下資料庫中簡體中文、繁體中文是否正常,不會出現亂碼。
SQL>select spid,spname,spshortname from spinfovisual_hk
…...
非常不幸,我看到了一堆亂碼,這也證明了Oracle不支援字元集從超集到子集的更改,當時心裡很緊張,很怕失敗,從而恢複到原樣。
但是根據以前的驗證,把UTF8下的備份匯入到ZHS16GBK中去,是OK的,所以繼續嘗試。
4. 匯入備份的使用者資料
還是以oracle使用者登陸UNIX, 先刪除庫中的使用者mmsc:
#sqlplus “/ as sysdba”
SQL>drop user mmsc cascade;
SQL>exit
再運行createuser.sql,產生mmsc使用者。
然後使用原來的備份檔案,匯入到mmsc使用者中:
注意:先設定NLS_LANG要與當前資料庫的一致:ZHS16GBK。這樣,匯出時使用者會話的NLS_LANG為UTF8,與原先的資料庫字元集一致;現在為ZHS16GBK,與此時的資料庫字元集一致。這樣,匯入時,就會進行字元轉換。
# export NLS_LANG = “SIMPLIFIED CHINESE_CHINA.ZHS16GBK”
#imp mmsc/mmsc@mdspdb file=DSMPD113_user_mmsc.dmp ignore=y fromuser=mmsc touser=mmsc
馬上查看資料庫中簡體、繁體中文,哈哈,沒有亂碼了,一切顯示正常。
緊接著進行驗證,也證明了:1個漢字此時只佔用2個字元長度。問題解決了!