MySQL 處理連接時的編碼流向:
Client (character_set_client)
↓ 轉換
Connection (character_set_connection)
↓ 轉換
Database/Table/Column (character_set_database)
↓ 轉換
Result (character_set_results)
核心原則:連接層字元集 ≥ 客戶端字元集 ≥ 結果字元集,且資料庫/表/列字元集 ≥ 連接層字元集,才能保證無損轉換。
-- 關鍵:客戶端用 gbk 輸入/顯示中文,連接層/庫用 utf8
SET character_set_client = gbk;
SET character_set_connection = utf8;
SET character_set_database = utf8;
SET character_set_results = gbk;
-- 驗證
SHOW VARIABLES LIKE 'char%';
解讀:
client=gbk:Windows CMD 默認 GBK,輸入中文正確編碼connection=utf8:內部處理用 UTF-8,容納所有字符results=gbk:輸出回 CMD 用 GBK 顯示正常
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
init_connect = 'SET NAMES utf8mb4' # 非超級用戶自動執行
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
⚠️ 注意:Windows 控制台若設置為 UTF-8 (chcp 65001),則 client/results 也應為 utf8mb4。
-- 資料庫
SHOW CREATE DATABASE db_name;
-- 表
SHOW CREATE TABLE table_name;
-- 列
SHOW FULL COLUMNS FROM table_name;
-- 資料庫級
ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;
-- 表級 (轉換現有數據)
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
-- 列級精確控制
ALTER TABLE table_name MODIFY COLUMN col_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
$dsn = "mysql:host=localhost;dbname=test;charset=utf8mb4";
$pdo = new PDO($dsn, 'user', 'pass', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_general_ci"
]);
$mysqli = new mysqli('localhost', 'user', 'pass', 'test', 3306);
$mysqli->set_charset('utf8mb4');
// 或
mysqli_set_charset($mysqli, 'utf8mb4');
| 框架 | 配置示例 |
|---|---|
| Laravel | 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci' in config/database.php |
| Spring Boot | spring.datasource.url=...&characterEncoding=utf8mb4&connectionInitSql=SET NAMES utf8mb4 |
| ThinkPHP | 'charset' => 'utf8mb4' in database config |
| Django | 'OPTIONS': {'charset': 'utf8mb4'} in DATABASES |
SELECT HEX(col), col FROM table WHERE id=? 確認儲存的十六進位為 UTF-8 編碼 (中文每字 3 字節,Emoji 4 字節)| 現象 | 根因 | 解決 |
|---|---|---|
| PMA 正常,CMD 亂碼 | CMD 編碼非 UTF-8,client/results 未設置 | CMD 執行 chcp 65001 或 SET NAMES gbk/utf8mb4 對應 |
| PHP 寫入正常,讀取亂碼 | 連接字串缺 charset、頁面 meta charset 缺失 | DSN 加 charset=utf8mb4、HTML |
| Emoji 存入變 ?? | 表/列為 utf8 (mb3) 非 utf8mb4 | ALTER TABLE ... CONVERT TO utf8mb4 |
| 歷史數據 latin1 存中文 | 雙重編碼 latin1→utf8 | 導出→iconv -f latin1 -t utf8→導入,或 CONVERT TO 配合 BINARY 過渡 |
| 修改 my.cnf 重啟無效 | 配置節點錯誤、被後載入文件覆蓋 | mysql --help | grep my.cnf 確認加載順序、檢查 [mysqld] 節點 |
SET NAMES utf8mb4 COLLATE utf8mb4_general_ciMySQL 中文亂碼不是玄學,而是字元集鏈路管理的缺失。遵循「utf8mb4 全棧統一、連接初始化 SQL 兜底、配置文件分層生效、驗證閉環測試」四步法,配合 HEX() 可視化驗證儲存編碼,即可徹底根治控制台、PMA、PHP 三端亂碼問題。記住:編碼問題 90% 是配置問題,10% 是歷史數據遷移問題。