数据库迁移后中文乱码本质是字符集链路断点所致,需分层验证数据源、传输通道、目标库的UTF-8(推荐utf8mb4)统一性,涵盖MySQL四级配置、JDBC连接参数、HEX字节比对及端到端读写测试。

数据库迁移后出现中文乱码,本质是字符集链路断点导致的——不是某一处错了,而是从数据源、传输通道到目标库多个环节的编码不一致叠加造成的。校验不能只看“存进去能不能读”,而要分层验证每个关键节点是否真正统一为 UTF-8(推荐)或目标字符集。
检查数据库层面的字符集配置
迁移后首先要确认 MySQL 实例、库、表、列四级字符集是否全部对齐:
- 查实例默认字符集:
SHOW VARIABLES LIKE 'character_set%';,重点关注character_set_server和collation_server - 查目标数据库:
SHOW CREATE DATABASE your_db;,确认DEFAULT CHARACTER SET是utf8mb4(不是旧版utf8) - 查具体表:
SHOW CREATE TABLE your_table;,确保建表语句含CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - 查字段级编码:
SELECT COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='your_db' AND TABLE_NAME='your_table';,避免个别字段仍是latin1或gbk
验证 JDBC 连接是否生效
即使数据库设对了,Java 应用若没正确声明编码,仍会走默认路径产生乱码:
- JDBC URL 必须显式携带参数:
?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai(utf8mb4才支持 emoji 和四字节 UTF-8 字符) - 避免使用已弃用的
characterEncoding=UTF-8(大小写敏感且部分驱动不识别),统一用小写utf8mb4 - 在代码中加一行验证:执行
SELECT @@character_set_client, @@character_set_connection, @@character_set_results;,三者都应返回utf8mb4
比对迁移前后实际字节内容
光看 SELECT 结果是否“显示正常”不可靠,需穿透到二进制层校验:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 在原库和新库分别执行:
SELECT HEX(column_name) FROM table WHERE id = ?;,对比十六进制输出是否完全一致(例如中文“你好”在 utf8mb4 下是E4BDA0E5A5BD) - 若新库 HEX 值变短(如变成
C4E3CAB8),说明被当 GBK 解析过;若出现3F3F3F(问号替换),说明插入时已丢失字节 - 导出迁移前后的 SQL 文件,用
file -i old.sql和file -i new.sql检查文件实际编码,排除 mysqldump 工具自身未指定--default-character-set=utf8mb4导致导出即损坏
模拟真实读写路径做端到端测试
写个最小可运行脚本,绕过所有中间框架,直连验证全链路:
- 用
DriverManager.getConnection(...)创建连接,不经过连接池 - 插入一条含中文、emoji、生僻字(如“?”)的记录
- 立即用同一连接
SELECT并打印getBytes(StandardCharsets.UTF_8).length和new String(bytes, StandardCharsets.UTF_8) - 若长度异常或抛
MalformedInputException,说明某处隐式转码失败
不复杂但容易忽略:迁移工具(如 DataGrip、Navicat、mysqldump + source)本身也有字符集选项,必须和数据库、JDBC 三方对齐。漏掉任意一环,校验就失去意义。

















