数据在存储(Latin1)和传输(GB2312)时的编码错误和修复:
🔍 问题根源分析
-
MySQL 实际存储
- 表字符集为
latin1
,但您通过 Navicat 的 连接属性选择 GB2312 导入数据时,Navicat 自动做了以下转换:
GB2312 → 二进制流 → 以 latin1 解码存储
- 由于
latin1
是单字节编码,这种操作相当于将 GB2312 的中文字符 伪装成 latin1 存储(实际数据未损坏)。
- 表字符集为
-
导出乱码原因
- 直接导出时,Navicat 默认用
latin1
解码数据,但数据本质是 GB2312 编码的二进制流,导致乱码。
- 直接导出时,Navicat 默认用
✅ 解决方案
方法 1:导出时强制指定二进制转换(推荐)
在 Navicat 导出向导中:
- 选择 "SQL 文件" 或 "CSV" 格式。
- 在 "高级" 选项卡中:
- 设置 "导出字符集" 为
GB2312
或GBK
。 - 勾选 "以二进制字段处理字符数据"(关键步骤)。
- 设置 "导出字符集" 为
方法 2:通过 SQL 命令导出修复
-- 1. 导出时用 HEX() 函数保留二进制原始数据
SELECT HEX(字段名) FROM 表名 INTO OUTFILE '/tmp/data.txt';
-- 2. 用 Python 或其他工具将 HEX 转换回 GB2312
import binascii
with open('/tmp/data.txt', 'r') as f:
data = binascii.unhexlify(f.read().strip()).decode('gb2312')
with open('/tmp/data_fixed.txt', 'w') as f:
f.write(data)
方法 3:彻底转码数据库
-- 1. 导出表结构(不含数据)
mysqldump -u root -p --no-data dbname > schema.sql
-- 2. 导出数据为 latin1 格式(保留二进制)
mysqldump -u root -p --default-character-set=latin1 --skip-set-charset --no-create-info dbname > data_latin1.sql
-- 3. 修改 schema.sql 中的表字符集为 GBK
sed -i 's/latin1/gbk/g' schema.sql
-- 4. 新建数据库并导入
mysql -u root -p -e "CREATE DATABASE dbname_gbk CHARSET gbk"
mysql -u root -p dbname_gbk < schema.sql
-- 5. 转换数据文件编码
iconv -f latin1 -t gbk data_latin1.sql > data_gbk.sql
mysql -u root -p dbname_gbk < data_gbk.sql
🛠 Navicat 操作关键截图指南
-
导入设置
(确保红框中的字符集选择 GB2312) -
导出设置
(勾选二进制选项并指定 GB2312)