根本原因是客户端连接时字符集协商失败,导致MySQL按latin1等错误编码解析中文字符串字面量,存入mysql.proc表即损坏;必须在CREATE PROCEDURE前执行SET NAMES utf8mb4,并确保my.cnf中[client]、[mysql]、[mysqld]三段均配置utf8mb4且重启服务。

直接结论:这不是存储过程语法或逻辑问题,而是客户端连接时字符集协商失败,导致MySQL在解析中文字符串字面量(如'你好')时读错字节,触发ERROR 1366 (HY000)或ERROR 1300 (45000)类报错并中断执行。
为什么SET NAMES utf8mb4必须在CREATE PROCEDURE之前执行
MySQL存储过程体内的字符串字面量(比如SELECT '测试')在创建阶段就被服务端按当前会话的character_set_client解码。如果该值是latin1或gbk,而你用UTF-8编码保存的SQL文件里写了中文,MySQL就会把两个UTF-8字节当做一个latin1字符处理,存进mysql.proc表时已损坏——后续任何调用都会出错或返回问号。
实操建议:
- 在命令行中创建前,先连上库执行:
SET NAMES utf8mb4; - 用脚本批量建过程时,把
SET NAMES utf8mb4;作为第一行,不要依赖配置文件 - 验证是否生效:
SHOW VARIABLES LIKE 'character\_set_client';,结果必须是utf8mb4 - Navicat/Workbench等工具需在连接属性里显式设置“Initial SQL”为
SET NAMES utf8mb4
my.cnf里三段配置不全或不一致的后果
只改[mysqld]段的character-set-server=utf8mb4,对存储过程乱码几乎没用。因为客户端(如mysql命令行、JDBC驱动)仍可能以latin1发起连接,服务端照单全收,过程体就废了。
常见错误现象:
-
mysql -u root -p登录后执行SHOW CREATE PROCEDURE p1;看到中文注释变成???? - 过程能创建成功,但一执行
CALL p1();就报Incorrect string value - 错误日志里出现
Warning: Invalid utf8mb4 character string
正确配置必须覆盖三段:
[client] default-character-set = utf8mb4 [mysql] default-character-set = utf8mb4 [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci init_connect = 'SET NAMES utf8mb4'
改完必须重启服务:systemctl restart mysqld,reload不生效。
Windows CMD下执行存储过程仍乱码的隐藏原因
即使配置全对、连接也设了utf8mb4,Windows默认CMD控制台编码是GBK(chcp 936),会导致mysql客户端输出中文时被系统转码成乱码,看起来像过程执行失败。
解决方法很简单,但极易被忽略:
- 在启动
mysql前,先运行:chcp 65001(切换到UTF-8) - 或者直接用Windows Terminal + PowerShell,它默认支持UTF-8
- 不要在CMD里用
mysql -e "CALL p1()"这种单行模式查结果,容易漏掉编码协商细节
最麻烦的地方不是配置本身,而是「过程体一旦存错就不可逆」——SHOW CREATE PROCEDURE显示的只是定义语句,看不出内部字符串是否已被错误解码。真要确认,得看执行时返回的内容,或用SELECT HEX('中文')在同一会话里对比编码行为。所以预防永远比修复重要。


















