字符集与排序规则是绑定的编码方式和比较逻辑,utf8mb4为真正UTF-8标准,兼容Unicode 13+及所有emoji;MySQL 8.0.1+默认采用utf8mb4_0900_ai_ci,推荐新项目使用;修改需覆盖服务器、数据库、表、字段、连接全链路。
字符集和排序规则不是两个并列概念,而是“编码方式”和“比较逻辑”的绑定关系:字符集决定能存什么字符,排序规则决定这些字符怎么比、怎么排。
MySQL 里没有独立的“编码设置”,所有字符处理都靠这对组合——比如 utf8mb4 是字符集,utf8mb4_0900_ai_ci 是它配套的排序规则。选错其中任何一个,都可能让你遇到乱码、WHERE 条件不生效、ORDER BY 排序错乱、甚至索引失效。
MySQL 的 utf8 实际是 utf8mb3(最多 3 字节),它根本存不了 emoji、部分生僻汉字、越南语带多重音符的字、数学符号等——这些都需要 4 字节编码。
utf8mb4 才是真正的 UTF-8,完全兼容 Unicode 13+,支持所有 emoji 和现代多语言场景latin1;MySQL 8.0.1+ 才默认用 utf8mb4 + utf8mb4_0900_ai_ci
Incorrect string value
INSERT INTO users (name) VALUES ('张三??');如果表用的是 utf8 或 latin1,这条就会失败。
同一字符集下,不同 collation 会影响 =、LIKE、ORDER BY 的行为:
utf8mb4_0900_ai_ci(MySQL 8.0+ 默认)
ai = accent insensitive(忽略重音,如 é = e) ci = case insensitive(不区分大小写,如 A = a) utf8m
b4_unicode_ci
_general_ci 更准,但比 _0900_ai_ci 老(UCA 4.0),对德语 ß/ss、土耳其语 i/I 处理不够完善 utf8mb4_bin
ORDER BY 会按字节序排,中文会乱序(比如“张”和“李”不按拼音排)SELECT * FROM users WHERE name = 'alice'; -- 在 _0900_ai_ci 下匹配 'Alice' 和 'ALICE'
SELECT * FROM users WHERE token = 'AbC123'; -- 在 _bin 下只匹配完全一致的 'AbC123',不匹配 'abc123'
ALTER DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
✅ 只改数据库的默认设置
❌ 不影响已有表、字段、索引、数据的实际编码
常见踩坑点:
latin1,字段仍是 varchar(255) latin1_swedish_ci,查询时隐式转换导致索引失效 CONVERT TO CHARACTER SET,但没加 MODIFY COLUMN,结果 TEXT/BLOB 类型字段没变 安全做法(以单表为例):
SHOW CREATE TABLE users;
SHOW FULL COLUMNS FROM users;
ALTER TABLE users MODIFY name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
最易被忽略的一点:客户端连接也要同步设对,否则 character_set_client、character_set_results 还是 latin1,照样乱码。连接时务必加参数:?charset=utf8mb4(JDBC/Python/PHP 均需显式指定)。
真正麻烦的从来不是“怎么改”,而是“改到哪一层”——服务器、数据库、表、字段、连接、甚至应用层字符串构造,只要有一环掉链子,字符问题就会在某个凌晨三点的订单导出里突然爆发。