触发器内字段比较报 illegal mix of collations 的根本原因是执行时连接层 collation_connection 与字段实际 collation 不一致,必须在触发器体中对所有字符串操作显式指定与字段定义完全匹配的 collate,包括 if 条件、函数参数及局部变量声明,且需逐字核对 collation 名称,不可依赖表定义或连接初始化设置。

触发器里字段比较报 Illegal mix of collations,根本不是触发器语法问题,而是触发器执行时上下文的校对规则和表字段不一致。必须在触发器体内部显式对齐,不能依赖表定义或连接层设置。
触发器内字段比较直接报错的典型场景
比如在 BEFORE INSERT 触发器中写:IF NEW.name = 'admin' THEN,而 name 字段是 utf8mb4_0900_as_cs,但触发器运行时 @@collation_connection 是 utf8mb4_general_ci,MySQL 就会拒绝隐式转换,立刻报错。
- 错误现象不止于
=,LIKE、IN、函数参数传入(如UPPER(NEW.name))都可能触发 - 即使表和数据库字符集全统一,触发器仍可能出错——因为触发器执行环境继承的是连接层的
collation_connection,不是字段本身的校对规则 -
SHOW CREATE TRIGGER看不到校对信息,必须用SELECT @@collation_connection在触发器内实际执行时验证
在触发器 SQL 里强制指定 COLLATE
所有涉及字符串比较或函数调用的字段,必须显式加 COLLATE,且值要跟字段定义完全一致。不能只写 COLLATE utf8mb4_unicode_ci 就完事,得查准字段真实 Collation。
- 先确认字段校对规则:
SHOW FULL COLUMNS FROM your_table LIKE 'name';,看Collation列值 - 在触发器中写成:
IF NEW.name COLLATE utf8mb4_0900_as_cs = 'admin' COLLATE utf8mb4_0900_as_cs THEN - 函数参数也要对齐:
IF UPPER(NEW.name COLLATE utf8mb4_0900_as_cs) = 'ADMIN' THEN - 避免对索引字段用
CONVERT()——它会让条件无法走索引,且返回类型变CHAR,后续再参与比较又可能二次出错
触发器参数和变量的校对规则继承陷阱
触发器里声明的局部变量(DECLARE v_name VARCHAR(50);)默认没有校对规则,一旦赋值来自不同 collation 的字段,就会带入源头规则;后续参与比较就容易崩。
- 声明变量时必须显式指定:
DECLARE v_name VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs; - 赋值时仍需
COLLATE对齐:SET v_name = NEW.name COLLATE utf8mb4_0900_as_cs; - 不要依赖
SET NAMES或连接初始化来“一劳永逸”——触发器运行时不会重跑init_connect,它只吃当前会话的@@collation_connection - 如果触发器调用了自定义函数,该函数返回值的 collation 默认继承第一个参数,和函数体内怎么写
COLLATE无关;必须在函数定义时就声明:RETURNS VARCHAR(50) CHARSET utf8mb4 COLLATE utf8mb4_0900_as_cs
上线前必须验证的三个校对层
触发器能跑通,不等于线上不出错。必须在真实连接配置下测试,尤其注意应用框架是否覆盖了连接参数。
- 查触发器执行时的实际环境:
SELECT @@collation_connection, @@character_set_client, @@character_set_results; - 查字段定义:
SHOW CREATE TABLE your_table;,确认name字段带COLLATE utf8mb4_0900_as_cs - 查应用连接字符串是否含
?charset=utf8mb4&collation=utf8mb4_0900_as_cs(JDBC/MyBatis/ORM 配置各不相同,不能只信文档) - 大表上的触发器,别在高峰期改;
ALTER TABLE ... MODIFY字段 collation 会锁表重建索引,和触发器无关但常被一起操作,容易误判根因
最易被忽略的一点:触发器里写的 COLLATE 必须和字段定义里的值**逐字匹配**,哪怕只是 _ai_ci 和 _as_cs 差一个字母,MySQL 也认为不兼容。别抄错,也别靠记忆——每次改之前先 SHOW FULL COLUMNS 确认。











