MySQL 啟用 utf8mb4 完整支援 Emoji 表情符號指南
MySQL 預設 utf8 僅支援 3 位元組字元(BMP 平面),無法儲存 4 位元組的 Emoji、生僻漢字等補充平面字元。升級至 utf8mb4 是現代應用標配,本文提供從資料庫、表、欄位到連線層的完整遷移清單。
一、版本需求與字元集對照
| 項目 | utf8 (utf8mb3) | utf8mb4 |
| MySQL 版本 | 所有版本 | 5.5.3+ |
| 最大位元組 | 3 bytes | 4 bytes |
| Unicode 覆蓋 | 基本多文種平面 (U+0000~U+FFFF) | 完整 Unicode (含補充平面 U+10000~U+10FFFF) |
| Emoji 支援 | ❌ | ✅ |
| 索引長度限制 | 767 bytes (InnoDB 預設) | 767 bytes (需開啟 innodb_large_prefix 才能 3072) |
二、四層配置完整修改清單
1. 伺服器層
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci -- 或 utf8mb4_unicode_ci
init_connect = 'SET NAMES utf8mb4'
character-set-client-handshake = FALSE -- 強制忽略客戶端字元集宣告
2. 客戶端層
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
3. 資料庫與表層
-- 新建資料庫
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
-- 遷移既有資料庫
ALTER DATABASE mydb CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;
-- 遷移既有表(會重建表,大表請用 pt-online-schema-change)
ALTER TABLE mytable CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
-- 僅修改欄位
ALTER TABLE mytable CHANGE col col VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
4. 連線驅動層(應用程式)
- JDBC:
jdbc:mysql://host:3306/db?characterEncoding=utf8mb4&useUnicode=true(5.1.13+ 自動識別)
- Python (PyMySQL/mysqlclient):
charset='utf8mb4'
- Go (go-sql-driver/mysql):
charset=utf8mb4,utf8 DSN 參數
- Node.js (mysql2):
charset: 'utf8mb4'
三、校驗規則選擇:_general_ci vs _unicode_ci
| 校驗規則 | 特點 | 建議場景 |
utf8mb4_general_ci | 速度快、簡單權重、不支援多語言精細排序(如德語 ß=ss) | 純 ASCII/中文/日文、高併發寫入、不需複雜排序 |
utf8mb4_unicode_ci (5.6+) | 遵循 UCA 標準、多語言正確排序、略慢 | 多語言應用、需正確排序(法文、德文、越南文等) |
utf8mb4_0900_ai_ci (8.0 預設) | Unicode 9.0、效能優化、支援無重音比較 | MySQL 8.0 新專案首選 |
四、遷移實戰檢查清單
- 備份:
mysqldump --default-character-set=utf8mb4 --single-transaction db > backup.sql
- 修改配置檔並
systemctl restart mysqld
- 執行 ALTER DATABASE / TABLE(大表用
pt-online-schema-change 避免鎖表)
- 檢查索引長度:
VARCHAR(255) utf8mb4 佔 768 bytes,超過 767 限制。解決:
SET GLOBAL innodb_large_prefix=ON; (5.7 預設 ON)
SET GLOBAL innodb_file_format=Barracuda;
ROW_FORMAT=DYNAMIC/COMPRESSED 建表
- 驗證:
INSERT INTO t(emoji) VALUES ('😀🎉🚀'); SELECT HEX(emoji) FROM t; 應見 F09F9880F09F8E89F09F9A80
- 應用層驗證:端到端寫入/讀取 Emoji,確認無亂碼、無截斷。
五、常見坑點彙總
- 舊版驅動:Connector/J 5.1.13 前不支援 utf8mb4,必須升級。
- 中間件:ProxySQL、MaxScale 需同步設定
charset=utf8mb4。
- 備份工具:
mysqldump 預設 utf8,必須加 --default-character-set=utf8mb4。
- 字串長度計算:應用層
strlen 可能按字節計算,Emoji 佔 4 字節,驗證邏輯需按字元數(CHAR_LENGTH)。