根本原因是MySQL的utf8实为utf8mb3,不支持4字节Unicode字符,应统一使用utf8mb4;需同时确保连接层(client/connection/results)、表定义、服务端配置(my.cnf)及应用连接参数均为utf8mb4,并重启服务验证。

MySQL插入中文乱码,根本原因不是“没设utf8”,而是utf8在MySQL里其实是utf8mb3,不支持4字节Unicode字符(比如大部分emoji、生僻汉字、部分繁体字)。真正该用的是utf8mb4——它才是标准UTF-8的完整实现。只改utf8,问题大概率还会复现。
确认当前连接和表的实际字符集
别猜,先查。乱码常出现在「连接层」或「表定义层」任一环节不匹配。执行:
SHOW VARIABLES LIKE 'character\_set%';
重点看这三项是否都是utf8mb4:character_set_client、character_set_connection、character_set_results。再查表:
SHOW CREATE TABLE your_table_name;
看DEFAULT CHARSET和COLLATE字段。如果出现latin1、utf8或utf8_general_ci,就明确是字符集没对齐。
一次性修正连接层:客户端、连接、结果集
临时生效(当前会话)可快速验证:
-
SET NAMES utf8mb4;—— 等价于同时设置character_set_client、character_set_connection、character_set_results - 若用JDBC,URL末尾加
?useUnicode=true&characterEncoding=utf8mb4;Spring Boot中配置spring.datasource.url时必须包含 - 命令行客户端启动时加参数:
mysql -u root -p --default-character-set=utf8mb4
注意:SET NAMES只对当前连接有效,程序重启或连接池重连后失效,所以必须在连接建立时就指定,不能靠运行时补。
修正表与数据库的存储层字符集
已有表不能只靠ALTER DATABASE,必须逐层改到底:
- 改库:
ALTER DATABASE your_db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; - 改表:
ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 单独改某列(如字段类型是
TEXT或VARCHAR):ALTER TABLE your_table_name MODIFY column_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
特别注意:CONVERT TO会重建表,大数据量需评估锁表时间;MODIFY更安全,但要显式写出完整字段定义(类型、长度、是否NULL等),否则可能丢失约束。
服务端配置必须同步更新
my.cnf 或 my.ini 里光写utf8没用,必须明确写utf8mb4:
[client] default-character-set = utf8mb4 [mysql] default-character-set = utf8mb4 [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci
改完必须重启MySQL服务(systemctl restart mysqld 或 net stop mysql && net start mysql),否则配置不加载。且重启后务必再跑一次SHOW VARIABLES LIKE 'character\_set%'确认六项全为utf8mb4——尤其是character_set_server,很多人漏查这一项。
最容易被忽略的是:即使服务端、表、连接全设成utf8mb4,如果应用代码里用了String.getBytes("UTF-8")再手动拼SQL(比如某些老Java工具类),而没声明连接编码,字节流仍可能被按默认平台编码(如Windows上的GBK)解码,导致二次乱码。这类场景必须从源头统一走连接参数控制,别绕过驱动。


















