標籤:gen 字典 ace random 查看 img ase char set
資料庫當前字元集為AL32UTF8,若打算將字元集更換為ZHS16GBK,執行如下命令:
"ALTER DATABASE NATIONAL CHARACTER SET INTERNAL_USE ZHS16GBK"
可以達到預期目標嗎?
我們通過一個實驗來看一看,執行上述命令,在資料庫層面到底發生了什麼。
在字元集為AL32UTF8的資料庫中,建立一張表,分兩個欄位分別插入一些漢字和一些可列印的字元。
1、建立表
create table TEST
(
id NUMBER, --記錄編號
name VARCHAR2(10 CHAR),--插入隨機產生的漢字串。產生方法見附件一。
key VARCHAR2(60) –插入隨機產生的可列印字串
)
2、插入50000條記錄
declare
leng number;
begin
for x in 1..5
loop
for y in 1..10000
loop
leng:=ceil(dbms_random.value(0,10));
insert into test values (y,gen_hanzi(leng),dbms_random.string(‘P‘,leng));
end loop;
commit;
end loop;
end;
3、隨機查看一些記錄值,以及在該字元集下的編碼
查詢漢字"擂"的UTF8編碼,
可知,資料庫當前對漢字確實是使用UTF8進行編碼。
4、資料庫執行轉換字元集命令
轉換之後,查詢當前資料庫的字元集:
可知,在資料字典層面,資料庫的字元集已合AL32UTF8轉為了ZHS16GBK。
資料字典層面進行了調整,那麼字元的編碼有沒有根據新的字元集進行調整呢?
可以看到,所有的DUMP值均沒有發生變化——即在磁碟儲存層面,資訊未發生任何變化。因為儲存上仍然在使用UTF8編碼,但解碼上使用GBK解碼,所以,漢字全部解碼錯誤(即沒有得到正確的漢字元號)。而對於可列印的字元,由於字元在兩種不同的字元集中,其編碼值一致,因此,未發生解碼錯誤。
從上述可知,如果目標字元集不是原字元集的超集,因為原編碼並未發生變化,則極有可能出現解碼錯誤而導致亂碼的現象。在上面,看到了相關漢字字元在UTF8字元集下的編碼值,那麼這些字元在GBK字元集下是如何編碼的呢?
將該表的記錄插入到使用ZHS16GBK字元集的資料庫中,查看記錄值及編碼值:
可以看到,GBK字元集對漢字是2位元組編碼,而UTF8對漢字是3位元組編碼。
我們還有另外一個問題——修改字元集之後,對於修改之前儲存的字元編碼無變化,那對於之後儲存的字元呢?
6、向修改字元集之後的資料庫中插入漢字與可列印的字元
插入100條記錄,為與之前記錄區別,其ID>10000。
declare
leng number;
begin
for y in 10000..10100
loop
leng:=ceil(dbms_random.value(0,10));
insert into test values (y,gen_hanzi(leng),dbms_random.string(‘P‘,leng));
end loop;
commit;
end;
查看插入的值,以及其編碼:
從第7條記錄的編碼長度,即可初步判斷其使用了GBK的編碼值。我們來驗證一下:
結論:
1、執行字元集轉換的命令會修改資料字典
2、執行字元集轉換的命令不為使用新的字元集為之前儲存的字元進行重新編碼。因為如果目標字元集不是原字元集的超集,轉換後可能(尤其是漢字)出現亂碼。
3、執行字元集轉換的命令後,將為之後輸入的字元使用新的字元集進行編碼。
附件——"產生隨機長度漢字串的預存程序"
產生隨機長度漢字串的預存程序:
create or replace function gen_hanzi(max_length number) return varchar2 as
leng number;
hanzi varchar2(1 char);
hanzis varchar2(4000):=‘‘;
begin
leng:=ceil(dbms_random.value(0,max_length));
for x in 1..leng
loop hanzi:=unistr(‘\‘||trim(to_char(ceil(dbms_random.value(19968,40869)),‘XXXX‘)));
hanzis:=hanzis||hanzi;
end loop;
return hanzis;
end;
Oracle轉換字元集操作到底發生了什嗎?