一次 Kettle 中文乱码写入失败的完整排查实录

今天在用 Kettle(PDI)做数据迁移时,踩了一个典型的中文编码坑。错误信息看起来挺吓人:

sql 复制代码
Incorrect string value: '\xC9\xDC\xD0\xCB\xCA\xD0...' for column 'content' at row 1

乍一看以为是目标库字符集问题,结果一路排查下来,发现根源藏得特别深。今天把整个过程记录下来,希望能帮到遇到同样问题的朋友。


起因:一个看似简单的数据同步任务

我的任务很明确:

  • 源库 :MySQL 8.0,IP 180.23.1.1:3306,库名 oldtest
  • 目标库 :另一个 MySQL 8.0 实例,端口 3315,库名 newtest
  • 工具:Kettle 7.1(别问为什么不用新版,老项目)

两个表结构几乎一样,content 字段都是 LONGTEXT 类型。我以为直接"表输入 → 表输出"就能搞定,结果一跑就报错。


第一阶段:误判为连接参数格式错误

最初报的错根本不是编码问题,而是:

python 复制代码
Invalid ID for region-based ZoneId, invalid format: Asia/Shanghai;Driver class=...

我一开始完全懵了:明明 URL 写得好好的,怎么 driver class 被拼进参数值里了?

🔍 排查过程

  • 反复检查 Custom URL,确认没有多余字符
  • 突然想到:会不会是 "Options" 表格里写了东西?
  • 打开一看------果然!之前测试时随手在 Options 里填过一行,Value 列不小心粘贴进了 Driver class=... 这种非法内容

解决 :清空 Options 表格,所有参数统一写进 Custom URL,用 & 分隔。

教训:Kettle 的 Options 表格和 Custom URL 是合并使用的,脏数据会污染整个连接串


第二阶段:真正的敌人------中文编码问题浮出水面

清理完连接参数后,能连上数据库了,但一写数据就报:

c 复制代码
Incorrect string value: '\xC9\xDC\xD0\xCB\xCA\xD0...' for column 'content'

\xC9\xDC 是啥?查了一下,这是 GBK 编码下"深"字的十六进制。说明数据源里存的是 GBK 字节,但 MySQL 当 UTF8 解析,自然失败。

🔍 初步判断

  • 源表声明是 utf8,但实际存的是 GBK 数据(历史遗留)
  • 目标表是 utf8mb4,理论上兼容,但前提是传入的是合法 UTF8 字符串

于是我在两个连接里分别加了编码参数:

  • 源库:characterEncoding=GBK
  • 目标库:characterEncoding=utf8

但还是失败!


第三阶段:被忽略的关键参数------useUnicode=true

这时候我开始怀疑人生:配置明明没错,为什么还是不行?

灵机一动,想起以前看过 MySQL JDBC 文档提到:从 5.1 开始,必须显式开启 Unicode 支持,否则 characterEncoding 可能被忽略

赶紧加上 useUnicode=true

text 复制代码
# 源库
jdbc:mysql://...?useUnicode=true&characterEncoding=GBK&...

# 目标库
jdbc:mysql://...?useUnicode=true&characterEncoding=utf8&...

改完之后,还是失败

我差点放弃,直到做了最后一件事------重启 Spoon

神奇的事情发生了:转换成功跑通,中文正常写入!


为什么重启才生效?

后来复盘发现,Kettle 7.1 有个隐藏坑点:

数据库连接对象会被缓存,即使你修改了 URL,旧的连接可能还在用

也就是说,我虽然改了连接配置,但 Kettle 内部仍然用着之前没加 useUnicode=true 的连接池实例。只有重启 Spoon,才能彻底清空缓存,让新配置生效。


最终验证:确保每一步都正确

为了保险,我在"表输入"和"表输出"之间加了个"写日志"步骤,打印 content 字段。看到控制台输出的是"深圳市某某单位"这样的正常中文,心里才踏实。

同时确认目标表确实是 utf8mb4

sql 复制代码
SHOW CREATE TABLE target_table;
-- 输出包含:CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci

经验总结

  1. 不要相信表的字符集声明

    很多老系统把 GBK 数据塞进 utf8 表,实际存储的是 GBK 字节。要通过 HEX(content) 验证真实编码。

  2. JDBC 连接必须显式开启 Unicode

    光写 characterEncoding=GBK 不够,一定要加 useUnicode=true

  3. Kettle 的 Options 表格是双刃剑

    宁可全写进 Custom URL,也不要混用,避免参数污染。

  4. 改完配置记得重启 Spoon

    Kettle 7.1 的连接缓存机制会让你误以为配置没生效。

  5. 用"写日志"步骤验证中间数据

    在关键节点打印字段值,能快速定位是读取问题还是写入问题。


附:推荐的完整连接配置

源库(读取 GBK 数据)

ini 复制代码
jdbc:mysql://180.23.1.1:3306/oldtest?
  useUnicode=true&
  characterEncoding=GBK&
  useSSL=false&
  allowPublicKeyRetrieval=true&
  serverTimezone=Asia/Shanghai

目标库(写入 UTF8MB4)

ini 复制代码
jdbc:mysql://180.23.1.1:3315/newtest?
  useUnicode=true&
  characterEncoding=utf8&
  useSSL=false&
  allowPublicKeyRetrieval=true&
  serverTimezone=Asia/Shanghai

连接类型选 Generic database ,Driver class 填 com.mysql.cj.jdbc.Driver,Options 表格留空。


这次排查花了我大半天时间,但搞清楚原理后,以后再遇到类似问题就能秒解。希望这篇记录能帮你少走弯路。

相关推荐
Java爱好狂.8 分钟前
Java面试Redis核心知识点整理!
java·数据库·redis·分布式锁·java面试·后端开发·java八股文
小程故事多_808 分钟前
开源界核弹级输出!蚂蚁 Agentar-Scale-SQL 凭 “编排式扩展” 技术,成为 Text-to-SQL 天花板
数据库·人工智能·sql·开源·aigc·embedding
程序员小假30 分钟前
我们来说一下消息的可靠性投递
java·后端
duangww37 分钟前
SAPUI5 1.71.78老版本的消费restful服务
后端·restful
用户85996816776942 分钟前
UE5虚幻引擎汽车HMI设计高级研修课
后端
用户85996816776943 分钟前
鸿蒙HarmonyOS多线程编程实战:AI语音
后端
谷隐凡二1 小时前
etcd在Kubernetes中的作用简单介绍
数据库·kubernetes·etcd
阿杆1 小时前
如何在 Spring Boot 中接入 Amazon ElastiCache
java·数据库·redis
开心猴爷1 小时前
iOS 应用发布流程中常被忽视的关键环节
后端
qq_343247031 小时前
单机版认证kafka
数据库·分布式·kafka