MySQL 有三处需要设置字符集
- 表和字段:数据以哪种字符集保存,例如
utf8mb4或latin1。MySQL 5.7 及更早版本的默认值是latin1,存不下中文。 - 连接:客户端和服务器之间用哪种字符集通信,用
SET NAMES utf8mb4或连接参数设置。 - 文件:导入或导出时文件的编码,在 phpMyAdmin 的导入页面中可以选择文件的字符集。
三处不一致,中文就会出错。最常见的有两种情况:
???:字段或连接是latin1,存不下中文,MySQL 把每个字都换成了?。这些文字已经丢失,只能从原始数据重新导入。我们:UTF-8 的中文经由latin1连接写进了latin1字段。在程序里看起来一切正常,phpMyAdmin 和导出文件里却是乱码。这种情况下字节还在,可以修复。
乱码
"1","å¼ ä¼Ÿ","北京市","13800138000"
修复后
"1","张伟","北京市","13800138000"
在 Windows 命令行中连接时
在简体中文 Windows 的 cmd 或 PowerShell 中运行 mysql 客户端时,控制台用的是 GBK(代码页 936)。即使数据库里的数据完全正确,查询结果也可能显示成 浣犲ソ 这样的乱码。这只是显示问题:先执行 chcp 65001 把控制台切换为 UTF-8,或用 mysql --default-character-set=gbk 让这次会话按 GBK 输出。不要为了让控制台显示正常而去改表的字符集。控制台的更多设置见 PowerShell 中文乱码。
检查字符集
SHOW VARIABLES LIKE 'character_set%';查看服务器和连接的设置。SHOW CREATE TABLE users;查看表和各个字段的字符集。SELECT name, HEX(name) FROM users LIMIT 5;查看实际保存的字节:在utf8mb4字段中,E4B8AD是“中”,而C3A4C2B8C2AD则是已经乱码的“中”。
修复导出文件
- 在 phpMyAdmin 中把表导出为 SQL 或 CSV,或者使用
mysqldump --default-character-set=utf8mb4。 - 把文件拖到上面的框中。Mojibuster 只修复乱码的部分,正常的中文保持不变。
- 在 改动了什么? 中确认修复的位置,然后下载文件。
- 导入到字符集为
utf8mb4的表中,导入时文件字符集选择utf-8。 - 先在副本上测试,再替换正式的表。
导出文件始终不会离开你的电脑,含有客户信息也可以放心处理。导出的 CSV 用 Excel 打开出现乱码时,请看 Excel 打开 CSV 乱码。
从根本上解决
- 新建表时指定
DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci。 - 程序的连接也要设为
utf8mb4,例如在 PHP 的 PDO DSN 中加上charset=utf8mb4,在 JDBC 连接串中加上characterEncoding=UTF-8。 - 如果
latin1字段里存的是 UTF-8 字节,不要直接用CONVERT TO转换,否则会再编码一次,变成双重乱码。安全的做法是先改为二进制类型:MODIFY name VARBINARY(255),再MODIFY name VARCHAR(255) CHARACTER SET utf8mb4。 - 不要使用 MySQL 的
utf8:它每个字符最多只存 3 个字节,保存 emoji 和部分生僻字时会报Incorrect string value错误。
常见问题
为什么程序里显示正常,phpMyAdmin 里却是乱码?
因为程序和数据库把同一个错误犯了两次:程序通过 latin1 连接写入 UTF-8,又用同样的方式读回来,所以看起来正常。phpMyAdmin 的连接是正确的,显示的才是真正保存的内容。
变成 ??? 的中文还能恢复吗?
不能。MySQL 在保存时就把存不下的字换成了 ?,原来的文字已经不在数据库里了。Mojibuster 也无法恢复,请从原始文件或备份重新导入。
MariaDB 也一样吗?
一样。MariaDB 的字符集设置和 MySQL 相同,命令也一样。
导出文件可以多大?
每个文件最大 100 MB。较大的数据库建议按表分别导出。