乱码根源在于客户端、连接层、表字段三者字符集未对齐;须同步配置character_set_client、connection、results为utf8mb4,改表用CONVERT TO,连接字符串必须显式声明charset=utf8mb4,SQL Server需加N前缀,文件BOM头亦致乱码。

乱码不是数据库不支持中文,而是字符集在客户端、连接层、表字段三者之间没对齐。只改其中一环,基本白忙。
查当前实际生效的字符集配置
别信配置文件或建库语句里的默认值,运行时可能被覆盖。连上 MySQL 后立刻执行:SHOW VARIABLES LIKE 'character_set%';
-
character_set_client:你发 SQL 时,MySQL 认为你用的编码 -
character_set_connection:连接层转码用的中间编码,必须和 client 一致 -
character_set_results:返回结果时用的编码
只要有一个是 latin1 或 utf8(注意不是 utf8mb4),插入中文就大概率变成 ??? 或 \xE6\x88\x91 这类错误。
改表字段必须用 CONVERT TO,不能只改表级声明
ALTER TABLE table_name CHARACTER SET utf8mb4 这种写法只改元数据,字段实际存储仍按旧编码,无效。
真正生效的是:
ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
- 大表会锁表、重建索引、临时磁盘空间翻倍,务必选低峰期
- 若字段有全文索引,
utf8mb4下单列索引长度上限是 767 字节,需配合innodb_large_prefix=ON和ROW_FORMAT=DYNAMIC - 只想改某列(比如
TEXT类型),用MODIFY更可控:ALTER TABLE t MODIFY content TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;,但必须重写完整字段定义,否则可能丢NOT NULL或DEFAULT约束
连接层不设 charset=utf8mb4,前面全白搭
即使数据库、表、字段全设成 utf8mb4,只要应用连接没声明字符集,MySQL 仍按 latin1 解析请求——这是最常被忽略的一环。
- PHP PDO:
mysql:host=localhost;charset=utf8mb4必须写进 DSN - Java JDBC:
jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=utf8mb4,注意&要转义,驱动建议用 8.0+ - 命令行 mysql 客户端:
mysql --default-character-set=utf8mb4 -u root -p,否则默认用latin1 - Navicat:右键连接 →「编辑连接」→「高级」→ 勾选「使用 MySQL 字符集」并选
utf8mb4
漏掉任何一处,character_set_client 就不会变成 utf8mb4,后续所有环节都跟着错。
SQL Server 插入中文必须加 N 前缀
SQL Server 不靠字符集声明,而靠 Unicode 字面量标记。即使字段是 NVARCHAR,漏写 N 也会触发隐式转换,导致乱码。
- 正确写法:
INSERT INTO users(name) VALUES(N'张三'); - 错误写法:
INSERT INTO users(name) VALUES('张三');—— 这会被当VARCHAR处理,再转NVARCHAR时已失真 - 所有参与
JOIN、WHERE、ORDER BY的字段,排序规则也必须统一为Chinese_PRC_CI_AS,否则报“无法解决排序规则冲突”
真正容易被忽略的是:SQL 文件本身带 BOM 头(EF BB BF)会让 mysql 客户端解析错位,英文正常、中文全乱——这种问题根本查不到字符集配置里,得用 hexdump -C file.sql | head -n 1 看前三个字节。

















