首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 亂碼遷移實戰:從 latin1/gb2312 升級至 utf8mb4 的排查與修復流程

     編輯:MySQL 資料庫相關知識

典型亂碼場景

  • 舊庫 (MySQL 4.x/5.0) 預設 latin1,實際存 GBK/GB2312
  • 升級至 5.5+/5.6+/5.7+,預設仍 latin1 或改為 utf8
  • 遷移/備份恢復後,中文變「????」、「鏈」、「游æˆ」

根因:字符集聲稱與實際存儲不一致

MySQL **不驗證** 寫入內容是否符合聲稱字符集。
latin1 = 單字節 → 實際存雙字節 GBK → 導出時若按 latin1 讀取再按 utf8 寫入 = 雙重錯誤編碼

修復三步走 (參考文章 89252 完整版)

1. 確認源庫實際編碼

SHOW CREATE TABLE t\G
-- 查看 DEFAULT CHARSET=latin1
SELECT col, HEX(col) FROM t WHERE col LIKE '%中文%';
-- HEX 應呈現 GBK 編碼 (如 D6D0 CEC4 = "中文" 的 GBK)

2. 正確導出導入流程

# 目標庫建為 utf8mb4
CREATE DATABASE new_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

# 導出結構 (去除 latin1)
mysqldump -u root -p --no-data --skip-set-charset old_db |
  sed 's/CHARSET=latin1/CHARSET=utf8mb4/g' > struct.sql
mysql -u root -p new_db < struct.sql

# 導出數據 (按 latin1 讀取 = 原始位元組)
mysqldump -u root -p --default-character-set=latin1 --no-create-info --skip-set-charset old_db > data.sql

# 導入數據 (按 GBK 解讀 → 存 utf8mb4)
mysql -u root -p --default-character-set=gbk new_db < data.sql

3. 升級過程中 my.cnf 關鍵配置

[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect = 'SET NAMES utf8mb4'
skip-character-set-client-handshake  # 強制統一,忽略客戶端請求

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

修改後必須重啟 MySQL,存儲過程需重建 (見文章 89251)。

常見誤操作避雷

誤操作後果正確做法
直接 ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4MySQL 認為數據是 latin1,執行 latin1→utf8 轉換,GBK 位元組被錯誤轉碼 → 永久損壞先 ALTER TABLE t CHARSET=utf8mb4 (只改元數據),再按上述流程重導數據
導出時加 --default-character-set=utf8強制 latin1→utf8 轉換,同樣損壞導出用 --default-character-set=latin1 (或不指定,視版本)
導入時不加 --default-character-set=gbkMySQL 按連線字符集 (通常 utf8) 解讀,產生亂碼導入必須顯式指定源數據實際編碼 (GBK/GB2312)
忽略 SET NAMES latin1 干擾導入時被覆蓋字符集聲明導出加 --skip-set-charset 或事後 sed '/SET NAMES/d'

驗證腳本

SELECT 
  col,
  HEX(col) AS hex_bytes,
  CHAR_LENGTH(col) AS char_len,
  LENGTH(col) AS byte_len,
  col = CONVERT(CONVERT(col USING latin1) USING gbk) AS is_gbk_in_latin1
FROM new_db.target_table
WHERE col LIKE '%中文%'
LIMIT 10;
-- 正常 utf8mb4: hex_bytes 如 E4B8ADE69687, char_len=2, byte_len=6, is_gbk_in_latin1=0

總結

MySQL 亂碼本質 = 聲稱編碼 ≠ 實際編碼。遷移鐵律:**導出按聲稱編碼 (latin1) 原樣讀出 → 導入按實際編碼 (GBK) 解讀 → 存儲為目標編碼 (utf8mb4)**。配置文件統一 utf8mb4 + 重啟 + 存儲過程重建,徹底斷根。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved