MySQL 中文亂碼的解決方法

MySQL 裡的中文變成 ???,或在 phpMyAdmin、Navicat 中顯示成 ³¯¤j¤å、我們 這類符號?通常是資料表、連線和匯入檔案的字元集不一致。匯出檔中的亂碼可以在上方直接修復,再把 MySQL 統一設成 utf8mb4,之後就不會再發生。

支援文字與以下檔案:

  • CSV
  • TXT
  • JSON
  • XML
  • SRT
  • VTT
  • TSV
  • MD
  • HTML
  • SQL
  • LOG

例如 Excel 匯出、資料庫備份、字幕或網站程式碼。

修復

  1. 拖入檔案或貼上文字
  2. 自動修復
  3. 複製或下載
或把檔案拖到這裡
  • 不必上傳。 檔案直接在瀏覽器中修復,不會離開你的裝置。

  • 伺服器位於歐盟。 Mojibuster 在 芬蘭(歐盟)的伺服器上運作,受《一般資料保護規則》(GDPR)規範。 GDPR 全文(EUR-Lex,英文)

MySQL 有三個地方需要設定字元集

  • 資料表與欄位:資料用哪種字元集儲存,例如 utf8mb4 或 latin1。MySQL 5.7 以前的預設值是 latin1,無法正確儲存中文。
  • 連線:用戶端和伺服器之間用哪種字元集溝通,以 SET NAMES utf8mb4 或連線參數設定。
  • 檔案:匯入或匯出時檔案的編碼,phpMyAdmin 的匯入頁面可以選擇檔案的字元集。

三者不一致,中文就會出錯。最常見的有三種情況:

  • ???:欄位或連線是 latin1,存不下中文,MySQL 把每個字都換成 ?。這些文字已經遺失,只能從原始資料重新匯入。
  • 我們:UTF-8 的中文透過 latin1 連線寫進了 latin1 欄位。程式裡看起來一切正常,phpMyAdmin 和匯出檔裡卻是亂碼。
  • ³¯¤j¤å:早期的 PHP 網站常把 Big5 文字直接存進 latin1 欄位,用 UTF-8 工具開啟時就會變成這樣。

後兩種情況位元組都還在,可以修復。

舊網站資料庫匯出的 CSV 中的一列(Big5 存在 latin1 欄位)

亂碼

"1","³¯¤j¤å","¥x¥_¥««H¸q°Ï","02-2720-8889"

修復後

"1","陳大文","台北市信義區","02-2720-8889"

在 Windows 命令提示字元中連線時

在繁體中文 Windows 的命令提示字元或 PowerShell 中執行 mysql 用戶端時,主控台使用的是 Big5(字碼頁 950)。即使資料庫裡的資料完全正確,查詢結果也可能顯示成亂碼。這只是顯示問題:先執行 chcp 65001 把主控台切換成 UTF-8,或用 mysql --default-character-set=big5 讓這次連線以 Big5 輸出。不要為了讓主控台顯示正常而去改資料表的字元集。主控台的其他設定請見 PowerShell 中文亂碼。

檢查字元集

  • SHOW VARIABLES LIKE 'character_set%'; 查看伺服器和連線的設定。
  • SHOW CREATE TABLE customers; 查看資料表和各欄位的字元集。
  • SELECT name, HEX(name) FROM customers LIMIT 5; 查看實際儲存的位元組:在 utf8mb4 欄位中,E4B8AD 是「中」,C3A4C2B8C2AD 則是已經變成亂碼的「中」;A4A4 是 Big5 的「中」。

修復匯出檔

  1. 在 phpMyAdmin 中把資料表匯出成 SQL 或 CSV,或使用 mysqldump --default-character-set=utf8mb4;Big5 存在 latin1 欄位的舊資料請用 --default-character-set=latin1 匯出,位元組才會原封不動。
  2. 把檔案拖到上方的框中。Mojibuster 只修復亂碼的部分,正常的中文保持不變。
  3. 在 變更了什麼? 中確認修復的地方,然後下載檔案。
  4. 匯入字元集為 utf8mb4 的資料表,匯入時檔案字元集選擇 utf-8。
  5. 先在副本上測試,再取代正式的資料表。

匯出檔不會離開你的電腦,含有客戶資料也可以放心處理。匯出的 CSV 用 Excel 開啟出現亂碼時,請看 Excel 開啟 CSV 亂碼。

從根本解決

  • 建立資料表時指定 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci。
  • 程式的連線也要設成 utf8mb4,例如在 PHP 的 PDO DSN 中加上 charset=utf8mb4,在 JDBC 連線字串中加上 characterEncoding=UTF-8。
  • 如果 latin1 欄位裡存的是 UTF-8 位元組,不要直接用 CONVERT TO 轉換,否則會再編碼一次,變成雙重亂碼。安全的做法是先改成二進位型別:MODIFY name VARBINARY(255),再 MODIFY name VARCHAR(255) CHARACTER SET utf8mb4。
  • 不要使用 MySQL 的 utf8:它每個字元最多只存 3 個位元組,儲存 emoji 和部分罕用字時會出現 Incorrect string value 錯誤。

常見問題

為什麼程式裡顯示正常,phpMyAdmin 裡卻是亂碼?

因為程式和資料庫把同一個錯誤犯了兩次:程式透過 latin1 連線寫入 UTF-8 或 Big5,又用同樣的方式讀回來,所以看起來正常。phpMyAdmin 的連線是正確的,顯示的才是實際儲存的內容。

變成 ??? 的中文還能救回來嗎?

不能。MySQL 在儲存時就把存不下的字換成了 ?,原本的文字已經不在資料庫裡。Mojibuster 也無法還原,請從原始檔案或備份重新匯入。

MariaDB 也一樣嗎?

一樣。MariaDB 的字元集設定和 MySQL 相同,指令也一樣。

匯出檔可以多大?

每個檔案最大 100 MB。較大的資料庫建議按資料表分別匯出。

更多說明