中文亂碼 90% 源於「字符集不一致」:庫/表/連接/應用/終端任一環節編碼不統一即會產生亂碼。本文建立「全鏈路 UTF-8」標準,覆蓋創建、導入、連接、應用四大場景,並提供排查清單與避坑指南。
utf8mb4(真正 4 字節 UTF-8,支援 Emoji),舊版用 utf8(實為 utf8mb3)。-- 庫 CREATE DATABASE `test` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -- 表 CREATE TABLE `user` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(50) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
character_set_server(可能被改)。-- 1. 設置會話編碼 SET NAMES utf8mb4; -- 等同於同時設定 client/connection/results -- 2. 修正庫/表默認編碼(若歷史庫非 utf8) ALTER DATABASE `db_name` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ALTER TABLE `tbl_name` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -- 3. 導入(文件必須為 UTF-8 編碼保存) LOAD DATA LOCAL INFILE '/path/utf8.txt' INTO TABLE tbl_name CHARACTER SET utf8mb4 FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n';
鐵律:**UTF-8 文件進 UTF-8 庫,GBK 文件進 GBK 庫,嚴禁跨編碼導入**。
# JDBC URL jdbc:mysql://host:3306/db?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai # PHP PDO $dsn = "mysql:host=host;dbname=db;charset=utf8mb4"; $pdo = new PDO($dsn, $user, $pass, [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"]); # Python PyMySQL conn = pymysql.connect(host='host', user='user', password='pass', db='db', charset='utf8mb4')
my.cnf 鎖定默認值[client] default-character-set = utf8mb4 [mysql] default-character-set = utf8mb4 [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_general_ci init_connect = 'SET NAMES utf8mb4' # 非超級用戶連接自動執行 skip-character-set-client-handshake # 強制忽略客戶端請求的字符集,以服務端為準
注意:skip-character-set-client-handshake 會導致某些老驅動無法協商字符集,謹慎啟用,優先靠驅動參數控制。
SHOW VARIABLES LIKE 'character_set%'; 確認 client/connection/results/database/server/system 均為 utf8mb4。SHOW CREATE TABLE tbl_name; 確認表/列字符集。SELECT HEX(col) FROM tbl_name LIMIT 1; 查看實際存儲字節(中文 UTF-8 為 3 字節/字,GBK 為 2 字節/字)。characterEncoding/charset。chcp 65001)。| 誤區 | 後果 | 正確做法 |
|---|---|---|
| 只改表字符集不改列 | 列仍保留舊字符集,新數據正常、舊數據亂碼 | ALTER TABLE ... CONVERT TO CHARACTER SET ... 連同列一起轉換 |
| 用 SET NAMES utf8 而非 utf8mb4 | Emoji/生僻字截斷報錯 | 全鏈路統一 utf8mb4 |
| 導入文件編碼與庫不一致 | 雙重轉碼導致不可逆亂碼 | 文件保存為 UTF-8(Notepad++/VS Code 右下角切換) |
| 依賴 my.cnf 默認值 | 實例遷移/升級後默認值變更導致不一致 | 建表/連接顯式指定,不依賴默認 |
遵循「庫表顯式指定、文件 UTF-8 保存、驅動參數鎖定、服務端兜底」四步法,徹底告別中文亂碼。