根本原因是字段COLLATION与连接环境不一致,必须三者对齐:字段、连接、存储过程内字面量均需统一collation,仅改其一无效。

存储过程里出现 Illegal mix of collations 或中文变问号,根本不是代码写错了,而是字段的 COLLATION 和当前连接环境对不上——必须两边同时“对齐”,只改一边没用。
查清冲突源头:先看字段实际用的 COLLATION
别猜,直接查。存储过程中涉及的字段(比如 ref_id、name)可能表面看着是 utf8mb4,但实际 COLLATION 是 utf8_unicode_ci,而你的连接默认走的是 utf8mb4_unicode_ci,MySQL 就会拒绝隐式转换。
执行这条语句,把所有相关字段的真实排序规则打出来:
SELECT
TABLE_NAME, COLUMN_NAME, COLLATION_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'your_db'
AND TABLE_NAME IN ('table_a', 'table_b')
AND COLLATION_NAME IS NOT NULL;- 如果结果里混着
utf8_unicode_ci和utf8mb4_unicode_ci,这就是冲突点 - 注意:
SHOW CREATE TABLE看的是表级定义,但字段级COLLATION可能被单独覆盖过 - 临时表、函数返回值、变量声明(如
DECLARE v_name VARCHAR(50))默认继承连接的collation,不继承字段
存储过程内避免隐式转换:显式指定 COLLATE
当过程里做字符串拼接、条件比较或插入临时表时,MySQL 会按“连接层 collation”去解释字面量(比如 '测试'),如果和字段 collation 不一致,就报错或索引失效。
安全写法是在字面量或变量后加 COLLATE,强制对齐字段的排序规则:
SELECT * FROM users WHERE username = '张三' COLLATE utf8mb4_unicode_ci;
- 不要写
_utf8mb4'张三' COLLATE utf8mb4_unicode_ci—— 前缀冗余且易出错 - 如果字段是
utf8_unicode_ci,就用对应 collation:'张三' COLLATE utf8_unicode_ci - 过程里拼接字符串时也得带上,比如:
CONCAT('ID:', id) COLLATE utf8mb4_unicode_ci - 临时表字段若需参与 JOIN,建表时就得明确指定:
tmp_name VARCHAR(100) COLLATE utf8mb4_unicode_ci
连接环境必须与字段 COLLATION 匹配
很多同学改了表、改了字段,过程还是乱码,问题就出在连接层没同步。MySQL 存储过程执行时,用的是调用时的连接上下文,不是创建时的。
- 命令行客户端连上后第一件事:
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;(注意:不是SET NAMES utf8mb4就完事) - 应用连接字符串里必须带参数:
?characterEncoding=utf8mb4&connectionCollation=utf8mb4_unicode_ci(JDBC) - Navicat / DBeaver 要在连接属性里勾选“使用 MySQL 字符集”并手动设为
utf8mb4,否则它可能偷偷用latin1发送查询 - 检查当前连接实际生效的设置:
SELECT @@character_set_client, @@collation_connection;—— 这两个值必须和你字段的COLLATION兼容(最好是完全一致)
为什么不能只靠 ALTER TABLE CONVERT TO?
ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci 看似一劳永逸,但它有三个隐藏风险:
- 它只改表和字段定义,不改已存在的存储过程体内的硬编码字符串的解释方式
- 如果字段原 collation 是
utf8_general_ci,转成utf8mb4_unicode_ci后,某些边界字符排序行为会变,可能影响业务逻辑 - 过程里用了
PREPARE+EXECUTE动态 SQL,里面的字符串仍按连接 collation 解析,和字段无关 - 最麻烦的是:线上大表执行
CONVERT TO会锁表,而加ALGORITHM=INPLACE又不一定支持所有 collation 切换
真正稳的做法是:字段 collation、连接 collation、过程内字面量 collation,三者保持一致。少一个,都可能在某次查询中突然崩掉。


















