utf8 在 MySQL 里根本不是真正的 UTF-8
MySQL 的
utf8字符集实际只支持最多 3 字节的 Unicode 字符,也就是 U+0000 到 U+FFFF 范围,不包含 emoji、部分中文生僻字(如“?”)、古汉字、数学符号等 4 字节字符。它只是个历史遗留命名错误,官方也承认这是个“误称”。
utf8mb4才是 MySQL 中真正完整的 UTF-8 实现,支持全部 Unicode 字符(U+0000–U+10FFFF)。
建表或改表时必须显式指定 utf8mb4
即使服务器默认字符集设为
utf8mb4,单个表、列仍可能沿用旧配置。常见遗漏点:
CREATE TABLE语句中未加
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci修改已有表时只改了表级字符集,漏掉
MODIFY COLUMN或
CHANGE COLUMN对字段重定义 索引字段长度超限:
VARCHAR(255)在
utf8mb4下,若用
utf8mb4_unicode_ci排序规则,索引长度按每字符 4 字节算,可能突破 InnoDB 单索引 767 字节限制(尤其在
innodb_large_prefix=OFF时)
正确做法示例:
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
但注意:这仅更新表和字段默认值,不改变已存在字段的定义;如需确保字段本身也生效,还需单独执行:
ALTER TABLE users MODIFY COLUMN name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
客户端连接必须同步设置 utf8mb4
只改服务端字符集没用,如果连接层(如 JDBC、PHP PDO、Python mysqlclient)没声明
charset=utf8mb4,数据写入/读取时仍会按
utf8解码,导致乱码或截断。典型错误现象: 插入 emoji 报错
Incorrect string value: '\xF0\x9F\x98\x80'...查出来字段显示为
???或空字符串 同一字段,命令行
mysql客户端能正常显示,应用却乱码
检查连接字符集是否生效:
SELECT @@character_set_client, @@character_set_connection, @@character_set_results;
三者都应返回
utf8mb4。否则需在连接字符串中显式指定,例如: JDBC:
?useUnicode=true&characterEncoding=utf8mb4PHP PDO:
charset=utf8mb4加入 DSN my.cnf 全局配置(仅对未显式覆盖的连接有效):
default-character-set = utf8mb4([client] 段)和
collation-server = utf8mb4_unicode_ci([mysqld] 段)
utf8mb4_unicode_ci 和 utf8mb4_0900_as_cs 的选择
排序规则影响大小写敏感性、重音处理和性能。MySQL 8.0+ 默认推荐
utf8mb4_0900_as_cs(accent-sensitive + case-sensitive),而
utf8mb4_unicode_ci是较老的、不区分大小写的通用规则。 需要精确匹配(如密码盐、token、唯一键校验)→ 选
_as_cs规则 用户昵称、文章标题等需模糊搜索 →
utf8mb4_unicode_ci或更现代的
utf8mb4_0900_ai_ci(accent-insensitive)更合适 已有系统升级时注意:更换 collation 可能导致唯一索引冲突(比如原来 “A” 和 “a” 被视为不同值,新规则下视为相同)
查看当前支持的规则:
SHOW COLLATION WHERE Charset = 'utf8mb4' AND Collation LIKE '%_ci' OR Collation LIKE '%_cs';真正麻烦的是存量系统改造——字段改了、表改了、连接改了,但某个老旧的定时脚本或第三方工具还在用
utf8连接,一跑就出错。这种地方往往藏得深,得靠日志里的报错字符和具体 SQL 上下文才能揪出来。
