存储过程中文乱码的根本原因是创建时未显式声明 CHARACTER SET utf8mb4,导致 MySQL 用错误字符集解析中文字符串字面量;必须在 CREATE PROCEDURE 后添加 CHARACTER SET utf8mb4,并确保连接层、客户端、脚本开头均设为 utf8mb4,旧过程需 DROP 后重建。

存储过程里中文变问号、方块,或 SHOW CREATE PROCEDURE 里注释已损坏——这不是数据库字符集设错了,而是创建过程时 MySQL 按错误字符集解析了你的中文字符串字面量,字节一错,后续所有配置都救不回来。
CREATE PROCEDURE 必须显式声明 CHARACTER SET utf8mb4
MySQL 默认用 character_set_database 解析存储过程体,而这个值常是 latin1 或过时的 utf8(即 utf8mb3),根本存不下「?」「?」这类四字节汉字。不加声明,SELECT '你好' 在入库那一刻就被截断或转义成乱码。
-
CREATE PROCEDURE p1() CHARACTER SET utf8mb4是硬性要求,不能省略 -
utf8≠utf8mb4:前者最多 3 字节,后者才完整支持 Unicode 四字节字符 - 即使数据库、表、连接层全设为
utf8mb4,没这句声明,过程体中文照样乱
SET NAMES utf8mb4 必须在 CREATE 前执行,且对每条建过程语句生效
很多脚本批量建过程时只在开头写一次 SET NAMES utf8mb4,但若中间有 DELIMITER 切换或跨会话执行,该设置就失效了。客户端(如 Navicat、Workbench)也得在连接属性里手动指定字符集为 utf8mb4,不能依赖默认。
- 命令行建过程:启动时加
--default-character-set=utf8mb4,比进库再SET更可靠 - SQL 脚本第一行必须是
SET NAMES utf8mb4;,再跟DELIMITER //和CREATE PROCEDURE - 验证当前会话三值是否一致:
SHOW VARIABLES LIKE 'character\_set%';,重点看character_set_client、character_set_connection、character_set_results是否全为utf8mb4
变量与 CONCAT 中文必须显式指定字符集
CONCAT() 不自己决定字符集,它按输入参数中“字符集优先级最高”的那个来定输出。如果拼接字段来自 latin1 表,或变量没声明字符集,整个结果就会被降级成 latin1,往 utf8mb4 字段 INSERT 就报 Incorrect string value。
- 声明变量时加
CHARACTER SET utf8mb4:DECLARE v_msg VARCHAR(200) CHARACTER SET utf8mb4; - 从表查出的字段若字符集不一致,先
CONVERT(col_name USING utf8mb4)再拼接 - 硬编码中文建议加前缀:
_utf8mb4'测试消息',避免隐式推导出错
别信“改完配置就万事大吉”,旧过程要 DROP 后重建
已经建好的过程,哪怕你把 my.cnf 全配成 utf8mb4、重启服务、改库改表,里面的中文字符串字节也早固化在 mysql.proc 表里了。SHOW CREATE 出来是问号,说明创建那一刻就错了。
- 必须先
DROP PROCEDURE IF EXISTS p1;,再确保连接字符集正确、加上CHARACTER SET utf8mb4重新CREATE - 图形工具执行后记得刷新对象列表,否则可能还在缓存旧定义
- 如果过程被其他对象(如事件、触发器)调用,重建前需确认依赖关系是否中断
最易被忽略的是:字符集不匹配不是“写入”和“读取”两端的问题,而是“解析定义”这一步就卡死了。只要 CREATE 那一刻没用 utf8mb4 解析,后面怎么补都只是在修表象。

















