首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL latin1 編碼陷阱:非標準 cp1252 超集導致 Java 解碼亂碼及修復方案

     編輯:MySQL 綜合教學

核心差異

MySQL 的 latin1 ≠ 標準 ISO-8859-1 (IANA) ≠ Windows CP1252。

  • 比 ISO-8859-1 多出 0x80-0x9F 範圍字符(如 0x80 歐元符號)。
  • 比 CP1252 多出 5 個字符:0x81, 0x8D, 0x8F, 0x90, 0x9D,MySQL 將它們映射到 Unicode 同碼位(U+0081 等)。

官方文檔確認:latin1 is the same as the Windows cp1252 character set ... except ... MySQL translates 0x81 to Unicode 0x0081, 0x8d to 0x008d, 0x8f to 0x008f, 0x90 to 0x0090, and 0x9d to 0x009d.

Java 端解碼失敗現象

// 錯誤:使用標準 CP1252 或 ISO-8859-1 解碼
String s = new String(bytes, "cp1252");  // 0x81/0x8D/0x8F/0x90/0x9D 會丟失或錯誤映射

修復工具類(精確處理 5 個特殊碼位)

private String convertMySQLLatin1(String s) {
    if (s == null) return null;
    try {
        int len = s.length();
        byte[] buf = new byte[len];
        for (int i = 0; i < len; i++) {
            char c = s.charAt(i);
            switch (c) {
                case 0x0081: buf[i] = (byte)0x81; break;
                case 0x008D: buf[i] = (byte)0x8D; break;
                case 0x008F: buf[i] = (byte)0x8F; break;
                case 0x0090: buf[i] = (byte)0x90; break;
                case 0x009D: buf[i] = (byte)0x9D; break;
                default:
                    buf[i] = Character.toString(c).getBytes("cp1252")[0];
            }
        }
        return new String(buf, "UTF-8");  // 或目標編碼
    } catch (UnsupportedEncodingException e) {
        log.error("charset convert error", e);
        return null;
    }
}

最佳實踐建議

  1. 新項目禁用 latin1:統一使用 utf8mb4,從庫、表、連接、應用全鏈路一致。
  2. 存量系統:在數據庫網關層或 ORM 擴展點統一調用上述轉換器,隔離業務代碼。
  3. 驗證手段:插入含 0x81 等字符的測試數據,經讀取轉換後與原文對比。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved