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


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

相关推荐
可乐ea1 小时前
从第一性原理构建 AI Agent:提示词、工具、技能与记忆全解剖
数据库·人工智能·工具调用·ai智能体·提示词工程·agent开发·智能体记忆
打工仔折腾 AI1 小时前
工业场景下时序库与实时计算一体化架构选型实践对比
java·开发语言·后端·python·性能优化·架构·ai agent 实战
东方护航数据恢复(深圳)1 小时前
医疗案例:HIS/PACS 数据库页损坏修复,医院不停诊完成恢复【东方护航数据恢复深圳店】
数据库·数据恢复·医疗·二次开盘
蜗牛互联网1 小时前
长任务多Agent共享文件系统的Manifest交接模式
java·人工智能·后端
lusklusklusk2 小时前
Oracle数据库基础之11_Duplicate和Dataguard和RAC
数据库·oracle
苏supper3 小时前
Spring Boot多环境配置与打包运行
spring boot·后端·spring
geovindu3 小时前
rust: Composite Pattern
开发语言·后端·设计模式·rust·组合模式
PHP实战开发录4 小时前
MySQL字段加索引为什么没变快
数据库·mysql·php·开发
SearchMan4 小时前
还有人不知道&和&&的区别?
后端
想用offer打牌4 小时前
Personal Agent爆火 - 它到底是个什么
人工智能·后端·ai编程