## 症状现象
备份文件导入新库后,中文内容全变成问号或乱码符号,英文数字完好。数据本身没丢——是在备份或恢复的某个环节,字符被错误编码转换过一次,转换是有损的,问号意味着字节已回不来了。排查的目标是找到链路上哪一环的字符集与上下游不一致,先止损再修复。
## 四层继承链
字符集要过的关卡有四层,任何一层错配都会出问题。第一层客户端层:执行导入导出的终端与会话,SSH 客户端编码、locale 环境变量,中文环境不对,屏幕显示先乱,但这一层只影响显示不影响存储。第二层连接层:客户端与服务器之间的连接字符集,mysqldump 的 default-character-set 参数、mysql 导入时的会话字符集。第三层库层:目标库的默认字符集。第四层表层:表与列的定义。备份导出时,dump 工具按连接字符集读取并写出文件;恢复时按导入连接的字符集解释文件内容——两头字符集不一致,转换错位就发生在这两次解释之间。
## 排查步骤
第一步确认备份文件的编码:file 命令或十六进制查看中文字段,确认是 UTF-8 还是别的编码。第二步确认导出时用的参数,特别是有没有指定 default-character-set。第三步确认目标端的库表字符集与导入会话字符集。第四步小样本试验:建一张测试表,按修正后的参数导入十行,查中文是否完好,再全量执行。
## 修复操作
还没全量导入的,带对参数重来一次,导出与导入两端都显式指定:
bash mysqldump --default-character-set=utf8mb4 mydb > mydb.sql mysql --default-character-set=utf8mb4 mydb < mydb.sql
显式声明覆盖一切默认推断,是链路里最可靠的一环。已经导成问号的:先别动原备份,问号是转换失败的占位,原字节还在备份文件里,按正确参数重新导入即可恢复。若原备份也被错误转换过(概率较低),回到更早一代的备份。
**预防。**备份脚本里参数显式化写死,不依赖任何默认值;恢复演练时必查中文字段;环境迁移时把两端字符集配置做成检查项。顺云云服务器上的数据库迁移,导出导入命令的字符集参数属于"永远要写"的那类,省略它们就是在给未来埋雷。