字符集不匹配是 MySQL 亂碼的首要元兇。修改字符集分為**會話級臨時**、**全域動態**、**配置檔永久**三個層次,影響範圍與持久性不同。本文提供完整指令集、驗證方法與避坑指南,解決 `utf8`/`utf8mb4` 混用、連線字符集不一致等經典問題。
| 層次 | 指令 | 生效範圍 | 持久性 | 適用場景 |
|---|---|---|---|---|
| 會話級 | SET NAMES 'utf8mb4';或分別 SET client/connection/results | 當前連線 | 斷線失效 | 測試、臨時腳本、應用連線池初始化 SQL |
| 全域動態 | SET GLOBAL character_set_server = 'utf8mb4';SET GLOBAL character_set_database = 'utf8mb4'; | 全實例 (新連線) | 重啟失效 | 緊急變更、驗證效果、無重啟權限 |
| 配置檔永久 | my.cnf / my.ini 修改 [client] [mysqld] 區段 | 全實例 (含重啟) | 永久 | 生產環境標準化部署 |
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect = 'SET NAMES utf8mb4' -- 非超級用戶連線自動執行
# 可選:強制所有表預設 utf8mb4 (新建表生效)
# skip-character-set-client-handshake -- 忽略客戶端請求字符集,強制服務端字符集 (慎用)
關鍵點:
ALTER DATABASE `db_name` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
-- 僅修改表預設字符集 (不影響現有欄位)
ALTER TABLE `tbl` DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
-- 連同現有字符欄位一併轉換 (會重建表,鎖表時間長,大表請用 pt-online-schema-change)
ALTER TABLE `tbl` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `tbl` MODIFY `col` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL;
注意:`utf8mb4` 索引鍵長度限制 767 bytes (InnoDB 預設) 或 3072 bytes (開啟 `innodb_large_prefix` + `ROW_FORMAT=DYNAMIC/COMPRESSED`)。`VARCHAR(255)` utf8mb4 佔 768 bytes > 767,**必須縮減長度至 191 或開啟 large_prefix**。
-- 1. 檢視實例級字符集變數
SHOW VARIABLES LIKE 'character_set_%';
SHOW VARIABLES LIKE 'collation_%';
-- 2. 檢視資料庫/表/欄位字符集
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='db_name';
SELECT TABLE_NAME, TABLE_COLLATION FROM information_schema.TABLES WHERE TABLE_SCHEMA='db_name';
SELECT COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='db_name' AND TABLE_NAME='tbl';
-- 3. 實際寫入測試
INSERT INTO `tbl`(`col`) VALUES ('測試😀Emoji');
SELECT HEX(`col`), `col` FROM `tbl` WHERE `col` LIKE '%😀%'; -- 應顯示 F0 9F 98 80 (utf8mb4 4 字節)
| 框架/驅動 | 配置位置 | 關鍵參數 |
|---|---|---|
| JDBC (MySQL Connector/J) | JDBC URL | jdbc:mysql://host:3306/db?characterEncoding=utf8mb4&connectionCollation=utf8mb4_unicode_ci |
| Python (PyMySQL/mysqlclient) | 連線參數 | charset='utf8mb4' |
| Go (go-sql-driver/mysql) | DSN | charset=utf8mb4,utf8 (雙寫相容) |
| Node.js (mysql2) | 連線配置 | charset: 'utf8mb4' |
| PHP (PDO/mysqli) | DSN / mysqli_set_charset | charset=utf8mb4 / mysqli_set_charset($link, 'utf8mb4') |
HEX(col) 看位元組)。字符集修改核心原則:**全鏈路統一 utf8mb4** (Server/Database/Table/Column/Connection/Application)。配置檔永久生效是基石,會話級 `SET NAMES` 是補充,遷移現有資料需謹慎規劃鎖表時間與索引長度限制。建立驗證腳本納入 CI/CD,杜絕亂碼回歸。