存储过程中文乱码的根本原因是创建时字符集错误,必须在create procedure前执行set names utf8mb4,并显式声明character set utf8mb4,同时确保客户端、连接和服务器三层配置均为utf8mb4,且sql文件保存为utf-8无bom编码。

存储过程里中文变问号、方块或直接报 Incorrect string value,基本不是语法写错了,而是创建那一刻字符集就错了——字节存进 mysql.proc 表就固化了,后续改配置、重启服务、甚至重建数据库都救不回来。
CREATE PROCEDURE 前必须执行 SET NAMES utf8mb4
MySQL 解析 CREATE PROCEDURE 语句时,完全按当前会话的 character_set_client 去解码你写的中文字符串(比如 SELECT '你好' 或注释里的汉字)。如果此时是 latin1 或 gbk,UTF-8 编码的「你好」两个字节会被错误解释,存进去就是乱码字节。
-
SET NAMES utf8mb4等价于同时设character_set_client = utf8mb4、character_set_connection = utf8mb4、character_set_results = utf8mb4,三者缺一不可 - 命令行建过程:启动时加
--default-character-set=utf8mb4比进库再SET更可靠 - SQL 脚本批量建过程:第一行必须是
SET NAMES utf8mb4;,不能只在开头写一次,中间有DELIMITER切换或跨会话执行时容易失效 - Navicat / Workbench:连接属性里必须手动选「字符集」为
utf8mb4,不能依赖默认值
CREATE PROCEDURE 语句末尾要显式声明 CHARACTER SET utf8mb4
即使库是 utf8mb4,MySQL 默认仍用 character_set_database 解析过程体。而这个值常是 latin1 或过时的 utf8(即 utf8mb3),根本存不下四字节 Unicode 字符。
- 正确写法:
CREATE PROCEDURE p1() CHARACTER SET utf8mb4 BEGIN ... END -
utf8≠utf8mb4:前者最多支持 3 字节字符,对 emoji 和部分生僻中文直接截断 - 旧过程已损坏?必须
DROP PROCEDURE IF EXISTS p1后重建,改配置无效 - 硬编码中文建议加前缀:
_utf8mb4'测试消息',避免隐式推导出错
过程内拼接中文要用 CONVERT(... USING utf8mb4) 或显式声明变量字符集
CONCAT() 不自己决定字符集,它按输入参数中「字符集优先级最高」的那个来定输出。如果拼接字段来自 latin1 表,或变量没声明字符集,整个结果会被降级成 latin1,往 utf8mb4 字段 INSERT 就报错。
- 声明变量时加
CHARACTER SET utf8mb4:DECLARE v_name VARCHAR(100) CHARACTER SET utf8mb4 - 从表查出的字段若字符集不一致,先
CONVERT(col_name USING utf8mb4)再拼接 - 动态 SQL 拼接(
CONCAT('SELECT * FROM t WHERE name = ''', @name, ''''))必须包CONVERT(@name USING utf8mb4),否则中间转码就丢字节 - 更稳写法:用
PREPARE stmt FROM ...; EXECUTE stmt USING @name,参数化传参天然二进制安全
检查并统一客户端、连接、服务端三层配置
只改 [mysqld] 段的 character-set-server = utf8mb4 是白改——它不影响客户端怎么连进来。真正起作用的是连接发起方读取的配置段。
-
[client]:影响所有客户端工具(mysql命令、mysqldump)默认字符集 -
[mysql]:专用于mysql命令行客户端,优先级高于[client] -
[mysqld]:必须配collation-server = utf8mb4_unicode_ci,否则排序异常 - 配置示例(
/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不生效
最易被忽略的点:SQL 脚本文件本身得保存为 UTF-8 无 BOM 编码;Navicat/Workbench 里复制粘贴的中文,如果编辑器用了 GBK 编码保存,再怎么设连接字符集也无济于事。










