java處理不同數(shù)據(jù)庫(kù)字符集的數(shù)據(jù)同步

字號(hào):

環(huán)境:
    DB-A字符集:US7ASCII
    DB-B字符集:ZHS16GBK
    需求:從DB-A中將一個(gè)表的中文數(shù)據(jù)通過(guò)JAVA定時(shí)任務(wù)同步到DB-B.
    DB-A庫(kù)中表的信息如下:
    CREATETABLEUSER_INFO(USER_IDnumber,USER_NAMEvarchar2(50));
    如果用一般的方式來(lái)SELECT,和INSERT,不管客戶端用什么樣的字符集,數(shù)據(jù)到DB-B上肯定會(huì)顯示亂碼.
    解決方法1(在數(shù)據(jù)庫(kù)實(shí)現(xiàn))
    解決思路:通過(guò)視圖將數(shù)據(jù)轉(zhuǎn)換成二進(jìn)制數(shù)據(jù),繞過(guò)字符集的轉(zhuǎn)換,然后讓目標(biāo)庫(kù)來(lái)讀取.
    1.在DB-A庫(kù)上創(chuàng)建視圖:
    createorreplaceviewview_user_info
    as
    selectuser_id,utl_raw.cast_to_raw(user_name)user_namefromuser_info;
    2.在DB-B庫(kù)上創(chuàng)建視圖:
    createorreplaceviewview_user_info_db_a
    as
    selectuser_id,utl_raw.cast_to_varchar2(user_name)user_namefromview_user_info@db_a;
    3.在DB-B庫(kù)上進(jìn)行數(shù)據(jù)讀取:
    selectuser_id,user_namefromview_user_info_db_a;
    這時(shí)顯示出來(lái)的數(shù)據(jù)才是正確的!
    其實(shí)就是:selectutl_raw.cast_to_raw('中華人民'),utl_raw.cast_to_varchar2('D6D0BBAAC8CBC3F1')fromdual;
    優(yōu)點(diǎn):對(duì)JAVA程序來(lái)說(shuō)是透明的,無(wú)所改動(dòng)代碼。
    數(shù)據(jù)提取時(shí),與客戶端字符集無(wú)關(guān)
    缺點(diǎn):增加數(shù)據(jù)庫(kù)CPU開(kāi)銷
    --Examda提示學(xué)習(xí)到方法:
    解決方法2(在JAVA實(shí)現(xiàn))
    使用JAVA的兩個(gè)函數(shù)來(lái)實(shí)現(xiàn):getBytes(),newString()
    先來(lái)看一下這兩個(gè)函數(shù):
    .getBytes(charset)
    這是java字符串處理的一個(gè)標(biāo)準(zhǔn)函數(shù),其作用是將字符串所表示的字符按照charset編碼,并以字節(jié)方式表示。
    注意字符串在java內(nèi)存中總是按unicode編碼存儲(chǔ)的。
    比如"中文",正常情況下(即沒(méi)有錯(cuò)誤的時(shí)候)存儲(chǔ)為"4e2d6587",
    如果charset為"gbk",則被編碼為"d6d0cec4",然后返回字節(jié)"d6d0cec4"。
    如果charset為"utf8"則最后是"e4b8ade69687"。
    如果是"iso8859-1",則由于無(wú)法編碼,最后返回"3f3f"(兩個(gè)問(wèn)號(hào))。
    .newString(charset)
    這是java字符串處理的另一個(gè)標(biāo)準(zhǔn)函數(shù),和上一個(gè)函數(shù)的作用相反,將字節(jié)數(shù)組按照charset編碼進(jìn)行組合識(shí)別,最后轉(zhuǎn)換為unicode存儲(chǔ)。
    參考上述getBytes的例子,"gbk"和"utf8"都可以得出正確的結(jié)果"4e2d6587",但iso8859-1最后變成了"003f003f"(兩個(gè)問(wèn)號(hào))。
    因?yàn)閡tf8可以用來(lái)表示/編碼所有字符,所以newString(str.getBytes("utf8"),"utf8")===str,即完全可逆。
    對(duì)于以上兩個(gè)函數(shù),我們可以有兩種用法來(lái)解決這個(gè)問(wèn)題:
    方法2.1
    a)無(wú)需關(guān)心客戶端NLS_LANG的設(shè)置
    b)從數(shù)據(jù)庫(kù)取出字符的二進(jìn)制編碼:
    selectuser_id,utl_raw.cast_to_raw(user_name)user_namefromuser_info;
    c)在java用其所newString(username,'GBK')轉(zhuǎn)成中文
    d)插入到目標(biāo)庫(kù)
    方法2.2(推薦)
    a)將JAVA客戶端NLS_LANG設(shè)置為US7ASCII
    b)從數(shù)據(jù)庫(kù)直接取出字段值
    selectuser_id,user_namefromuser_info;
    (這時(shí)因?yàn)榭蛻舳撕头?wù)器的字符集一致,所以會(huì)得到正確的中文顯示)
    c)將中文進(jìn)行轉(zhuǎn)碼為GBK:
    newString(user_name.getBytes("gbk"),"gbk")
    d)得到正確的GBK中文編碼插入到目標(biāo)庫(kù)
    優(yōu)點(diǎn):代碼完全由JAVA控制,無(wú)需作數(shù)據(jù)庫(kù)變更,數(shù)據(jù)庫(kù)的壓力轉(zhuǎn)移到了JAVA客戶端.
    注意:必須把客戶端的字符集和服務(wù)器端的字符集設(shè)置成一樣