MySQL 有三個地方需要設定字元集
- 資料表與欄位:資料用哪種字元集儲存,例如
utf8mb4或latin1。MySQL 5.7 以前的預設值是latin1,無法正確儲存中文。 - 連線:用戶端和伺服器之間用哪種字元集溝通,以
SET NAMES utf8mb4或連線參數設定。 - 檔案:匯入或匯出時檔案的編碼,phpMyAdmin 的匯入頁面可以選擇檔案的字元集。
三者不一致,中文就會出錯。最常見的有三種情況:
???:欄位或連線是latin1,存不下中文,MySQL 把每個字都換成?。這些文字已經遺失,只能從原始資料重新匯入。我們:UTF-8 的中文透過latin1連線寫進了latin1欄位。程式裡看起來一切正常,phpMyAdmin 和匯出檔裡卻是亂碼。³¯¤j¤å:早期的 PHP 網站常把 Big5 文字直接存進latin1欄位,用 UTF-8 工具開啟時就會變成這樣。
後兩種情況位元組都還在,可以修復。
亂碼
"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 的「中」。
修復匯出檔
- 在 phpMyAdmin 中把資料表匯出成 SQL 或 CSV,或使用
mysqldump --default-character-set=utf8mb4;Big5 存在latin1欄位的舊資料請用--default-character-set=latin1匯出,位元組才會原封不動。 - 把檔案拖到上方的框中。Mojibuster 只修復亂碼的部分,正常的中文保持不變。
- 在 變更了什麼? 中確認修復的地方,然後下載檔案。
- 匯入字元集為
utf8mb4的資料表,匯入時檔案字元集選擇utf-8。 - 先在副本上測試,再取代正式的資料表。
匯出檔不會離開你的電腦,含有客戶資料也可以放心處理。匯出的 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。較大的資料庫建議按資料表分別匯出。