數據庫字符國際化是大家提問最多的問題,例如MySQL數據庫大家可能在JDBC-URL添加useUnicode=true&CharacterEncoding=GBK作為中文支持的基本條件。但這有時破壞了數據的完整性,假如某些人粗心大意,就會導致數據編碼錯誤,產生亂碼。因此,我們需要一些手段在程序內部進行編碼處理。人們一般通過在應用上使用 String(bytes:byte[], enc:String)/String.getBytes(enc:String)進行字符串編解碼,這樣做雖然易懂,但是假如碰到大字段表格,手動編碼時費時費力。
我的方法:通過研究JDK類庫,可以感覺到多層處理機制在數據處理上的優越性。我們完全有可能在數據庫上建立一個中間層用于字符的國際化處理,我就是這么做的。仔細研究一下JDBC操作數據庫出現字符編碼問題的根源,很輕易發現多數情況是ResultSet的幾個String方法在作怪,因此我們就完全可以編寫一個ResultSet中間層進行國際化處理,源碼如下:
public class I18nResultSet implements ResultSet{
PRivate String encoding;
private ResultSet rs;
public I18nResultSet(ResultSet rs, String encoding) throws java.io.UnsupportedEncodingException{
//檢查該編碼名稱是否被系統支持。
"".getBytes(encoding);
this.rs = rs;
this.encoding = encoding;
}
… …
//以下幾個方法是進行String字符串的重編碼.
public String getString(int index) throws SQLException{
String data = null;
try{
data = new String(rs.getBytes(index), encoding);
}catch(java.io.UnsupportedEncodingException uee){}
}
public String getString(Stirng field) throws SQLException{
String data = null;
try{
data = new String(rs.getBytes(field), encoding);
}catch(java.io.UnsupportedEncodingException uee){}
}
public void updateString(int index, String value) throws SQLException{
try{
rs.updateBytes(index, value.getBytes(encoding));
}catch(java.io.UnsupportedEncodingException uee){}
}
public void updateString(String field, String value) throws SQLException{
try{
rs.updateBytes(field, value.getBytes(encoding));
}catch(java.io.UnsupportedEncodingException uee){}
}
… …
}
package com.yipsilon.crocodile.database;
import java.sql.ResultSet;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.io.UnsupportedEncodingException;
/**
* 作者 yipsilon
* 如要轉載, 請通知作者
*/
public class I18nResultSetHandler implements InvocationHandler{
private ResultSet rs;
private String encoding;
public I18nResultSetHandler(ResultSet rs, String encoding) throws UnsupportedEncodingException{
this.rs = rs;
"".getBytes(encoding);
this.encoding = encoding;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable{
String methodName = method.getName();
if(methodName.equals("getString")){
Object obj = args[0];
if(obj instanceof Integer){
return decodeString(rs.getBytes(((Integer)obj).intValue()), encoding);
}else{
return decodeString(rs.getBytes((String)obj), encoding);
}
}else if(methodName.equals("updateString")){
Object obj = args[0];
if(obj instanceof Integer){
rs.updateBytes(((Integer)obj).intValue(), encodeString((String)args[1], encoding));
}else{
rs.updateBytes((String)obj, encodeString((String)args[1], encoding));
}
return null;
}
return method.invoke(rs, args);
}
private String decodeString(byte[] bytes, String enc){
try{
return new String(bytes, enc);
} catch(UnsupportedEncodingException uee){
return new String(bytes);
}
}
private byte[] encodeString(String str, String enc){
try{
return str.getBytes(enc);
} catch(UnsupportedEncodingException uee){
return str.getBytes();
}
}
}
ResultSet rs = ... ; //原始的ResultSet結果集
String encoding = "GBK"; //字符編碼
(ResultSet)Proxy.newProxyInstance(rs.getClass().getClassLoader(),
rs.getClass().getInterfaces(),
new I18nResultSetHandler(rs, encoding));
新聞熱點
疑難解答