一次 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 表格留空。


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

相关推荐
凌览9 分钟前
一键去水印|5 款免费小红书解析工具推荐
前端·javascript·后端
expect7g10 分钟前
Paimon源码解读 -- PartialUpdateMerge
大数据·后端·flink
申阳15 分钟前
Day 16:02. 基于 Tauri 2.0 开发后台管理系统-项目初始化配置
前端·后端·程序员
bcbnb16 分钟前
游戏上架 App Store 的完整发行流程,从构建、合规到审核的多角色协同指南
后端
JavaGuide17 分钟前
美团2026届后端一二面(附详细参考答案)
java·后端
aiopencode17 分钟前
无需源码的 iOS 加固方案 面向外包项目与存量应用的多层安全体系
后端
语落心生22 分钟前
Apache Geaflow推理框架Geaflow-infer 解析系列(六)共享内存架构
后端
语落心生25 分钟前
Apache Geaflow推理框架Geaflow-infer 解析系列(七)数据读写流程
后端
语落心生27 分钟前
Apache Geaflow推理框架Geaflow-infer 解析系列(五)环境上下文管理
后端