必须在create procedure前执行set names utf8mb4,因中文字符串在客户端发送时即按character_set_client解析并固化进mysql.proc表,若为latin1或utf8mb3则存入即损坏,后续任何配置修改均无法修复。

CREATE PROCEDURE 前必须执行 SET NAMES utf8mb4
存储过程里的中文字符串(比如 SELECT '你好'、COMMENT '日志记录')是在客户端发送 SQL 时就被解析并固化进 mysql.proc 表的。如果此时 character_set_client 是 latin1 或 utf8(即 utf8mb3),MySQL 会把 UTF-8 编码的汉字字节按错误编码解释,存进去就是损坏数据——后续改任何配置都救不回来。
实操建议:
- 在执行
CREATE PROCEDURE语句前,**显式加一行**:SET NAMES utf8mb4; - 命令行导入脚本时,这行必须是第一行,不能靠
my.cnf自动生效 - 用 Navicat / Workbench 等 GUI 工具时,检查连接属性里是否启用了「使用 UTF8MB4」或手动执行该语句后再建过程
- 避免在过程中临时切字符集,比如
SET character_set_results = latin1;,会污染后续输出
my.cnf 必须同时配 [client]、[mysql]、[mysqld] 三段
只在 [mysqld] 段写 character-set-server = utf8mb4 是无效的。它只影响新建库/表的默认值,不影响客户端怎么连进来——而存储过程创建依赖的是「连接发起时」的字符集。
三段作用差异:
-
[client]:控制所有客户端工具(mysql、mysqldump)的默认字符集 -
[mysql]:专用于mysql命令行客户端,优先级高于[client] -
[mysqld]:服务端行为,需同步设collation-server = utf8mb4_unicode_ci避免排序异常
Linux 下典型配置(/etc/my.cnf):
[client] default-character-set = utf8mb4 [mysql] default-character-set = utf8mb4 [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci
改完必须 systemctl restart mysqld,reload 不生效。
存储过程体内部要声明 CHARACTER SET utf8mb4
即使连接层和建库建表都对了,过程体内的局部变量、临时表、字符串拼接仍可能因隐式转换出问题。MySQL 允许在 CREATE PROCEDURE 语句中显式声明字符集,语法位置敏感:
-
CHARACTER SET utf8mb4必须放在COMMENT和LANGUAGE SQL之间 -
COLLATE utf8mb4_unicode_ci虽非强制,但建议加上,避免与字段校对规则不一致引发隐式转换警告 - 该声明会影响过程内所有未显式指定字符集的字符串常量、局部变量和临时表字段
示例片段:
CREATE PROCEDURE log_action(
IN p_user_id INT,
IN p_action VARCHAR(100)
)
COMMENT '记录用户操作'
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci
LANGUAGE SQL
BEGIN
INSERT INTO user_log (user_id, action_desc)
VALUES (p_user_id, CONCAT('用户执行了:', p_action));
END
验证过程体是否真按 utf8mb4 加载
SHOW CREATE PROCEDURE 只显示原始定义语句,看不出中文是否被正确解析。真正要确认,得看运行时行为:
- 调用后查结果字段是否为问号或 Mojibake(如
æ‘们) - 过程里用
SELECT '测试中文' INTO @tmp;再SELECT @tmp;,观察输出 - 检查
information_schema.routines中routine_definition字段内容是否已乱码(说明创建时就坏了)
最容易被忽略的是:**过程一旦创建失败或部分损坏,不能靠 ALTER 修改,必须 DROP 后重建,并确保重建全程都在 utf8mb4 连接上下文中进行。**











