核心結論:utf8 是偽 UTF-8,utf8mb4 才是真 UTF-8
| 特性 | utf8 (MySQL 別名 utf8mb3) | utf8mb4 |
| 最大字節數 | 3 字節 | 4 字節 |
| Unicode 覆蓋 | 基本多文種平面 (BMP, U+0000~U+FFFF) | 全部 17 個平面 (U+0000~U+10FFFF) |
| Emoji 支持 | ❌ 存入報錯/截斷 | ✅ 完美支持 |
| 生僻字支持 | ❌ U+10000 以上無法存儲 | ✅ 全支持 |
| 空間佔用 | 略小 | CHAR 類型固定 4 字節/字符 |
| 兼容性 | 歷史遺留 | utf8 超集,無縫遷移 |
歷史根因
- MySQL 早期實現 UTF-8 時,Unicode 標準尚未擴展輔助平面,以為 65535 字符足夠
- 為節省空間,
CHAR(n) 按最大字節數預分配,3 字節上限鎖定至今
- 5.5.3 引入 utf8mb4 修正,但為向後兼容保留 utf8 別名
遷移指南:零風險升級到 utf8mb4
1. 修改配置文件
[mysqld]
character_set_server = utf8mb4
collation_server = utf8mb4_general_ci
[client]
default_character_set = utf8mb4
[mysql]
default_character_set = utf8mb4
2. 庫表字符集轉換
SHOW VARIABLES LIKE 'character_set%';
-- 核心 6 項均為 utf8mb4
-- 實測 Emoji
CREATE TABLE t (c VARCHAR(10) CHARSET utf8mb4);
INSERT INTO t VALUES ('😀🎉');
SELECT c, HEX(c), CHAR_LENGTH(c) FROM t;
-- HEX: F09F9880F09F8E89, CHAR_LENGTH: 2
避坑清單
- ❌ 僅修改
my.cnf 不執行 CONVERT TO → 現有列仍為 utf8
- ❌ 連接字符串仍用
utf8 → 寫入時隱式轉換截斷
- ❌ 使用
utf8mb4_bin 排序規則導致大小寫敏感不符合業務預期 → 推薦 utf8mb4_general_ci 或 utf8mb4_0900_ai_ci (8.0+)
- ✅ 全鏈路一致:Server → Database → Table → Column → Connection → Application