1. 从两个字母开始:utf8mb4_general_ci 到底管什么
我帮人排查过一个注册功能 bug,现象很典型:用户明明没重复注册,系统却提示“邮箱已被占用”。查到最后,问题出在 utf8mb4_general_ci 这个排序规则上——它把 Admin@example.com 和 admin@example.com 判定成了同一个值,唯一索引直接拦截。类似的坑我在不同项目里见过不止一次,所以这次围绕 utf8mb4_general_ci 做个完整梳理,把排序规则的作用、对比、实操和排障一次讲清楚。适合刚接触 MySQL 的开发者,也适合正在做数据库迁移、字符集统一的老手。
1.1 字符集管“存什么”,排序规则管“怎么比”
很多开发者把 utf8mb4_general_ci 当成一个整体来看,觉得它只是“支持 emoji 的字符集配置”。实际上它由两部分组成:字符集 utf8mb4 和排序规则 general_ci。字符集决定的是数据的“存储形态”,例如字符 你 在 UTF-8 编码下对应某个字节序列;排序规则决定的则是数据“比较和排序”时的行为,例如在查询 WHERE name = 'admin' 时,Admin 算不算匹配。
我习惯用一个生活类比:字符集像是“一套字典的收字范围”,规定哪些字能写进去;排序规则像是“查字典时的排序方式”,规定按笔画、按拼音、还是按字母顺序来排。同一个字,用不同的排序规则,前后顺序和是否相等都可能不一样。MySQL 的规则是先有字符集,再有基于这个字符集的一组排序规则,所以 utf8mb4_general_ci 明确告诉数据库:存储使用 UTF-8 四字节编码,比较时使用 general 这组简化规则,并忽略大小写。
1.2 utf8mb4、general、ci 分别代表什么
先从名字开始拆。utf8mb4 是一种字符集,全称是 UTF-8 MultiByte 4,每个字符最多占用 4 个字节。老项目里常见的 utf8 实际是 utf8mb3 的别名,最多只能存 3 字节,遇到生僻的 CJK 扩展字符、emoji 这类需要 4 字节编码的内容就会乱码或报错。utf8mb4 就是为了补齐这个缺口,在 MySQL 5.5.3 之后引入。
