存储过程中文变问号或方块,根本原因是character_set_client、connection、results三者未统一为utf8mb4;create procedure时mysql按character_set_client解析中文字面量,若为latin1等则存入即损坏,必须在创建前执行set names utf8mb4并确保my.cnf中client[mysqld]三段均正确配置。

存储过程里中文变问号或方块,不是过程写错了,而是客户端连进来时就用错了编码——必须让 character_set_client、character_set_connection、character_set_results 三者同时为 utf8mb4,缺一不可。
为什么 SET NAMES utf8mb4 必须在 CREATE PROCEDURE 前执行
MySQL 解析 CREATE PROCEDURE 语句时,会按当前 character_set_client 去解码你写的中文字符串字面量(比如 SELECT '你好' 或注释里的中文)。如果此时是 gbk 或 latin1,那两个汉字的 UTF-8 字节就会被错误解释,存进 mysql.proc 表时已损坏,后续怎么改配置都救不回来。
- 即使全局
character_set_server=utf8mb4,旧版命令行客户端默认仍以latin1连接 -
SET NAMES utf8mb4等价于同时设置 client/connection/results,是创建前最轻量、最可靠的补救 - 脚本批量建过程时,第一行必须是
SET NAMES utf8mb4;,不能靠配置文件“自动生效”
my.cnf 配置必须覆盖 [client]、[mysql]、[mysqld] 三段
只改 [mysqld] 段的 character-set-server=utf8mb4 是无效的——它只影响新建数据库的默认值,不影响客户端怎么连进来。真正起作用的是连接发起方读取的 [client] 和 [mysql] 段。
-
[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
改完必须重启 MySQL:systemctl restart mysqld,reload 不生效。
验证三值是否统一,别只看 character_set_server
执行 SHOW VARIABLES LIKE 'character\_set%'; 后,重点盯住这三项:
-
character_set_client:你发过去的 SQL 里中文怎么被 MySQL 读的 -
character_set_connection:MySQL 内部转换时用的中间编码 -
character_set_results:返回结果(包括SHOW CREATE PROCEDURE输出)怎么编码给你的
只要其中任一值不是 utf8mb4,存储过程里的中文就可能乱码。常见陷阱:
- 用 JDBC 连接时漏了
useUnicode=true&characterEncoding=utf8mb4 - PHP 的
mysqli未调用$mysqli->set_charset('utf8mb4') - 某些 GUI 工具(如旧版 Navicat)连接参数里没勾选 UTF-8
最易被忽略的一点:存储过程体内的字符串字面量('测试')、注释、甚至分号后的空格,在创建那一刻就被固化进系统表;一旦当时编码错,后期再怎么改配置、ALTER DATABASE 都无济于事——只能 DROP PROCEDURE 后用正确连接重写。











