亂碼根因分析
中文亂碼本質是 編碼不一致:資料庫存儲編碼、表/欄位編碼、連線編碼、應用輸出編碼、瀏覽器解碼,任一環節不匹配即產生亂碼。
完整字元集配置鏈路
| 層級 | 配置位置 | 關鍵設定 | 驗證命令 |
| 伺服器 | my.cnf [mysqld] | character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci | SHOW VARIABLES LIKE 'character_set_server'; |
| 資料庫 | 建庫語句 | CREATE DATABASE db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; | SHOW CREATE DATABASE db; |
| 資料表 | 建表語句 | CREATE TABLE t (...) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; | SHOW CREATE TABLE t; |
| 欄位 | 建表/修表 | col VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci | SHOW FULL COLUMNS FROM t; |
| 連線 | 客戶端/驅動 | SET NAMES utf8mb4; 或連線屬性 characterEncoding=utf8mb4 | SHOW VARIABLES LIKE 'character_set_connection'; |
| 應用輸出 | HTTP Header / Meta | Content-Type: text/html; charset=utf-8 | 瀏覽器開發工具 Network 標籤 |
各語言/框架連線配置範例
PHP (PDO)
$dsn = "mysql:host=127.0.0.1;dbname=test;charset=utf8mb4";
$pdo = new PDO($dsn, 'user', 'pass', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"
]);
Java (JDBC / HikariCP)
jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai
# HikariCP
dataSource.dataSourceProperties.useUnicode=true
dataSource.dataSourceProperties.characterEncoding=utf8mb4
Python (PyMySQL / mysqlclient)
conn = pymysql.connect(host='127.0.0.1', user='root', password='pass',
db='test', charset='utf8mb4')
Go (go-sql-driver/mysql)
dsn := "user:pass@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
常見誤區與避坑
| 誤區 | 正確做法 |
使用 utf8 (MySQL 別名,僅 3 位元組) | 必須用 utf8mb4 (真正 UTF-8,4 位元組,支援 Emoji) |
只設定伺服器 character-set-server | 連線層 SET NAMES utf8mb4 同樣關鍵 |
JDBC URL 用 characterEncoding=utf8 | 必須 utf8mb4 (驅動 5.1.47+ 支援) |
| 修改 my.cnf 後未重啟 | 動態參數 SET GLOBAL 僅影響新連線,舊連線需重連 |
| 資料已亂碼入庫 | 無法單純修改編碼修復,需重新匯入正確編碼資料 |
遷移 latin1/gbk → utf8mb4 實戰
# 1. 導出 (指定來源編碼避免雙重轉碼)
mysqldump --default-character-set=latin1 --skip-set-charset -u root -p db > dump.sql
# 2. 檔案級轉碼 (若原檔為 gbk)
iconv -f gbk -t utf8 dump.sql > dump_utf8.sql
# 3. 修正建表語句字元集 (sed 批次替換)
sed -i 's/CHARSET=latin1/CHARSET=utf8mb4/g; s/CHARSET=gbk/CHARSET=utf8mb4/g' dump_utf8.sql
# 4. 匯入 (指定目標編碼)
mysql --default-character-set=utf8mb4 -u root -p db < dump_utf8.sql
驗證腳本
mysql -u root -p -e "
SELECT
@@character_set_server AS server,
@@character_set_database AS database,
@@character_set_connection AS connection,
@@character_set_client AS client,
@@character_set_results AS results,
@@collation_server AS collation;"