MySQL 中文亂碼本質是編碼不一致:存儲編碼、連接編碼、客戶端編碼三者任一不匹配即產生亂碼。本文通過實戰案例,演示如何診斷編碼錯位、導出修正、統一全鏈路編碼。
-- 查看庫表定義
SHOW CREATE DATABASE account; -- DEFAULT CHARSET=utf8
SHOW CREATE TABLE user; -- DEFAULT CHARSET=utf8
-- 查看數據(顯示亂碼)
SELECT * FROM user LIMIT 10;
-- realname: è€...
-- 系統變量顯示均為 utf8
SHOW VARIABLES LIKE '%char%';
-- character_set_client/connection/database/results/server/system = utf8
SET NAMES latin1;
SELECT * FROM user LIMIT 10;
-- realname: 陳、王嘉文、網家鋒... <-- 正常顯示!
結論:數據實際按 latin1 編碼存儲,但表定義聲明 utf8,導致「雙重編碼」錯位。
mysqldump -uroot -p --default-character-set=latin1 account user > /tmp/user.sql
user.sqlSET NAMES latin1 改為 SET NAMES utf8mysql -uroot -p -S /tmp/mysql3306.sock account < user.sql
SELECT * FROM user LIMIT 10; -- 中文正常顯示
my.cnf 未配置 character-set-server=utf8CHARSET=utf8SET NAMES utf8 或 mysqli::set_charset('utf8')<meta charset="utf-8">、終端編碼、編輯器編碼需統一[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
推薦 utf8mb4:支援 Emoji 及完整 Unicode,utf8 實為 utf8mb3。
CREATE DATABASE mydb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE TABLE t (c VARCHAR(100)) CHARSET=utf8mb4;
-- PHP (mysqli)
$mysqli = new mysqli('localhost', 'user', 'pass', 'db');
$mysqli->set_charset('utf8mb4');
-- PHP (PDO)
$pdo = new PDO('mysql:host=localhost;dbname=db;charset=utf8mb4', 'user', 'pass');
-- Java (JDBC)
jdbc:mysql://localhost:3306/db?characterEncoding=utf8&useSSL=false
-- 步驟 1:臨時表以二進制存儲
ALTER TABLE t MODIFY col VARBINARY(255);
-- 步驟 2:轉換為 utf8mb4
ALTER TABLE t MODIFY col VARCHAR(255) CHARACTER SET utf8mb4;
SET NAMES 僅影響當前會話,重連失效,必須在連接池初始化/重連時執行--default-character-set,否則按連接編碼導出,可能加重錯位中文亂碼的本質是編碼鏈路斷點。建立「服務器→庫表→連接→應用→前端」全鏈路 utf8mb4 標準,新項目從遷移存量數據時按「二進制中轉」法處理,可徹底告別亂碼。