MySQL存储过程中文乱码本质是客户端连接、服务端解析、结果返回三环节字符集不一致,关键在character_set_client、connection、results未统一为utf8mb4,需从连接初始化、配置文件、SQL文件编码三方面同步解决。

存储过程中文乱码本质是连接层字符集不一致
MySQL 存储过程本身不存“编码”,乱码发生在调用时的客户端连接、服务端解析、结果返回三个环节中。关键在于 character_set_client、character_set_connection、character_set_results 这三者不统一,尤其当它们被设为 gbk 或 latin1,而你的过程体里写了中文注释或 SELECT '你好' 这类字面量时,就会出问题。
常见现象:存储过程创建成功,但执行后返回结果中中文变成问号、方块,或直接报错 Incorrect string value;也可能在 SHOW CREATE PROCEDURE 中看到中文注释已损坏。
- 不要只改
character_set_server或数据库/表字符集——那对过程体内的字符串字面量无效 - 必须确保客户端发起连接时就协商好 UTF-8 兼容编码(推荐
utf8mb4) - 如果用命令行
mysql客户端,启动时加-D和--default-character-set=utf8mb4参数比进库后再SET NAMES更可靠
创建存储过程前必须 SET NAMES utf8mb4
即使全局配置了 utf8mb4,某些客户端(如旧版 JDBC、PHP mysqli 默认行为)仍可能以 latin1 建连。此时你写的 CREATE PROCEDURE p1() BEGIN SELECT '测试'; END,MySQL 会按 latin1 解析那两个汉字字节,存进 mysql.proc 表时就已损坏。
实操建议:
- 在创建过程前,显式执行:
SET NAMES utf8mb4; - 验证当前会话三值是否一致:
SHOW VARIABLES LIKE 'character\_set%';,重点看character_set_client、character_set_connection、character_set_results是否全为utf8mb4 - 如果用脚本批量建过程,把
SET NAMES utf8mb4;放在第一条语句,不要依赖配置文件
my.cnf 配置必须覆盖 [client]、[mysql]、[mysqld] 三段
只在 [mysqld] 段写 character-set-server=utf8mb4 不够——那是服务端默认值,不影响客户端怎么连进来。很多乱码问题根源就在 [client] 和 [mysql] 段缺失或写错。
正确配置示例(注意路径和权限):
[client] default-character-set = utf8mb4 [mysql] default-character-set = utf8mb4 [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci
修改后必须重启 MySQL:/etc/init.d/mysqld restart 或 systemctl restart mysqld;仅 reload 配置不生效。
-
default-character-set在[client]和[mysql]段才有效;[mysqld]段要用character-set-server - 别写
utf8——它是utf8mb3别名,不支持 emoji 和部分生僻汉字,2026 年还用它等于主动埋雷 - 如果用 Docker,确保
my.cnf被挂载且容器内路径正确,别只改宿主机却没生效
ALTER PROCEDURE 无法修复已损坏的过程体
一旦过程体里的中文因错误字符集被存成乱码字节,ALTER PROCEDURE 不会重新解析源码,只是改元数据。你看到的 SHOW CREATE PROCEDURE 输出仍是坏的。
唯一可靠做法是:
- 先用
SHOW CREATE PROCEDURE proc_name\G确认是否已损坏(看中文是否显示为 ? 或乱码) - 如果已损坏,用
DROP PROCEDURE IF EXISTS proc_name;删除 - 确保当前会话已执行
SET NAMES utf8mb4; - 再用原始 SQL 重建,注意 SQL 文件本身也得是 UTF-8 编码(编辑器别存成 GBK)
这个点最容易被忽略:以为改完配置、重启服务就一劳永逸,结果旧过程还在默默输出乱码。











