查清表和字段真实collation是第一步,需用show full columns和show create table确认实际定义,而非依赖注释或界面显示,text、json、虚拟列等均需显式指定collation。

查清表和字段真实 collation 是第一步
错误不是配置没生效,而是 MySQL 8.0 在执行 FIND_IN_SET、JOIN ON、UNION 或子查询时,会直接比对两边字段的 collation,不走 collation_server。你得看实际定义,不是看建表语句里的注释或 phpMyAdmin 界面显示:
- 用
SHOW FULL COLUMNS FROM your_table;查每列的Collation值 - 用
SHOW CREATE TABLE your_table;看表定义里是否显式写了旧规则(比如COLLATE utf8mb4_general_ci) - 特别注意
TEXT类型字段——它也能带 collation,且同样参与比较 -
SELECT @@collation_database, @@collation_server;只反映连接默认值,对已有字段无效
ALTER TABLE MODIFY 是修复字段 collation 的唯一可靠方式
临时加 COLLATE utf8mb4_0900_ai_ci 到 SQL 里能绕过单条报错,但不解决数据层不一致。批量修复必须落到字段定义上:
- 对普通字段:用
ALTER TABLE t MODIFY col VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; - 对已建索引的长字段(如
VARCHAR(500)),要检查前缀长度是否超限:utf8mb4_0900_ai_ci的索引长度计算更严格,可能需调小前缀(例如从191改为180) - 别漏掉虚拟列或 JSON 字段:像
JSON_VALUE(data, '$.field' RETURNING CHAR(100) COLLATE utf8mb4_0900_ai_ci)必须显式声明 collation -
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci会统一整张表,但无法覆盖字段级单独指定的旧 collation,得配合MODIFY补漏
跨版本迁移或主从复制时报 Unknown collation 怎么办
MySQL 5.7 和 MariaDB 都不认识 utf8mb4_0900_ai_ci,导入 dump 文件时直接卡死。不能只靠编辑器“全部替换”,必须定位真实使用位置:
- 用
grep -n "utf8mb4_0900_ai_ci" your_dump.sql扫描,重点关注三类行:CREATE DATABASE后的DEFAULT COLLATE、每个CREATE TABLE末尾的COLLATE、以及列定义后紧跟的COLLATE utf8mb4_0900_ai_ci - 安全替换目标选
utf8mb4_general_ci(5.7 原生支持)或utf8mb4_unicode_ci(兼容性好,但确认 5.7.7+ 是否启用innodb_large_prefix=ON) - 别替换成
utf8_general_ci:它绑定的是utf8(即utf8mb3)字符集,emoji 插入会失败 - 若导出时用了
--skip-set-charset,还要检查并替换SET NAMES utf8mb4 COLLATE utf8mb4_0900_ai_ci这类语句
FIND_IN_SET 和 JSON_VALUE 必须显式统一 collation
MySQL 8.0 对隐式转换更保守,宁可报错也不静默降级。这两个函数最容易被忽略:
-
FIND_IN_SET()返回值默认继承第一个参数的 collation;若第二个参数来自不同 collation 的字段或变量,就会触发Illegal mix of collations - 写成
FIND_IN_SET(col1 COLLATE utf8mb4_0900_ai_ci, @var COLLATE utf8mb4_0900_ai_ci)才真正生效 -
JSON_VALUE()在 8.0 中要求显式声明返回类型与 collation,不能只写JSON_VALUE(data, '$.field') - 连接层也要同步:在应用连接 URL 中加
?charset=utf8mb4&collation=utf8mb4_0900_ai_ci,否则 ORDER BY 或索引可能失效
最容易被跳过的其实是 SHOW CREATE TABLE 输出里的 collation 注释——它可能带 utf8mb4_0900_ai_ci,但字段定义里没写,导入到 5.7 就炸;反过来,8.0 导出时若没清理旧注释,也会让迁移脚本误判。真实 collation 只认字段定义和表定义里白纸黑字写的那部分,其余全是干扰项。











