中文亂碼是 Java 應用對接 MySQL 時最常見的坑。根因在於 MySQL 預設字符集為 latin1 (ISO-8859-1),而 Java 內部使用 Unicode (UTF-16)。當無法修改資料庫配置(如共享主機、受管雲資料庫)時,必須在應用層透過編碼轉換解決。
錯誤示範:直接 pstmt.setString(1, "中文"),資料庫呈現 ??。
正確做法:在寫入前手動轉碼:
String str = "中文"; // 關鍵步驟:將 Unicode 字串按 ISO-8859-1 重新編碼 str = new String(str.getBytes(), "ISO8859_1"); String sql = "INSERT INTO Tb (xxx) VALUES (?)"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, str); pstmt.executeUpdate();
getBytes() 無參數時使用平台預設編碼(通常為 UTF-8),再用 ISO8859_1 解碼,產生的字串在 MySQL 視為 latin1 正確存儲。
String str = rs.getString(1);
// 方式一:還原為平台預設編碼(通常 UTF-8)
str = new String(str.getBytes("ISO8859_1"));
// 方式二:指定目標編碼(如 GBK)
str = new String(str.getBytes("ISO8859_1"), "GBK");
原理:從資料庫讀回的字串實際為 latin1 位元組序列,先用 getBytes("ISO8859_1") 取回原始位元組,再按目標編碼解碼。
若擁有資料庫控制權,應從源頭修正:
ALTER DATABASE db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;jdbc:mysql://host:3306/db?useUnicode=true&characterEncoding=utf8&autoReconnect=truemy.cnf):[client] default-character-set = utf8mb4 [mysql] default-character-set = utf8mb4 [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci
採用 utf8mb4 可完整支援 Emoji 及補充字符。
characterEncoding=utf8 同時使用會導致雙重編碼,反而產生亂碼。總結:無法改配置時,應用層 ISO8859_1 轉碼是救命稻草;有權限時,統一全鏈路 utf8mb4 才是正道。