遇到 Oracle 資料庫字元集為 US7ASCII 時,JDBC 讀取中文會出現亂碼。本文記錄排查過程、解決方案,並深入探討不同字元集下中文位元組佔用差異。
SIMPLIFIED CHINESE_CHINA.US7ASCIIojdbc14.jar經測試,雙層轉碼可修正:
// 錯誤嘗試:單層轉碼無效
new String(fieldValue.getBytes("ISO-8859-1"));
// 正確寫法:指定源編碼與目標編碼
String correctValue = new String(fieldValue.getBytes("ISO-8859-1"), "GBK");
原理:US7ASCII 環境下,驅動以 ISO-8859-1 讀取位元組流,實際內容為 GBK 編碼中文,需先還原位元組再按 GBK 解碼。
缺點:所有中文欄位皆需手動轉碼,維護成本高。
在客戶端機器設定系統環境變數:
變數名:NLS_LANG 值:SIMPLIFIED CHINESE_CHINA.ZHS16GBK
重啟應用程式後,JDBC 自動按正確字元集交換資料,無需修改代碼。
註冊表同樣可設:HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\HOME0\NLS_LANG
| 字元集 | 中文位元組數 | 說明 |
|---|---|---|
| US7ASCII | 1 (但實際存儲異常) | 僅支援 ASCII,中文存儲會損壞 |
| ZHS16GBK | 2 | 簡體中文常用,GBK 超集 |
| ZHT16BIG5 | 2 | 繁體中文常用 |
| AL32UTF8 | 3 | Unicode UTF-8,中文佔 3 位元組 |
| UTF8 (Oracle 舊版) | 3 | Oracle 歷史 UTF-8 實作,非標準 |
將 US7ASCII 庫中文遷移至 AL32UTF8 庫時,原 VARCHAR2(20) 欄位存 10 個中文會報錯:
解決:擴充欄位長度或改用 NVARCHAR2(按字元計長度,中英同為 1 字元)。
SELECT LENGTH('汗'), LENGTHB('汗') FROM DUAL;
-- LENGTH 回傳字元數,LENGTHB 回傳位元組數
AL32UTF8NLS_LANG,避免應用層處理編碼LENGTHB 實測位元組長度