一、业务场景
实时消费 Kafka Topic 内 JSON 格式消息,通过 JsonPath 解析嵌套 JSON 字段,SQL 做日期格式化、生成主键、新增入库时间,最终批量写入 Oracle 业务表,采用流式任务持续同步。 使用版本:SeaTunnel 2.x(通用 HOCON 配置格式) 数据流链路:Kafka Source(JSON消息) -> JsonPath解析 -> SQL转换加工 -> JDBC Oracle Sink
二、完整可用 conf 配置(Kafka -> Oracle)
文件名:kafka2oracle_stream.conf
bash
env {
# 并行度根据消费速度调整,调试阶段设1方便定位数据
parallelism = 1
# 流式持续消费kafka,必须STREAMING
job.mode = "STREAMING"
}
source {
Kafka {
plugin_output = "fuji"
# kafka消息整体为json格式
format = json
topic = "XX"
bootstrap.servers = "XX"
consumer.group = "seatunnel_group"
kafka.config = {
client.id = "client_1"
# 单次拉取最大条数,提升同步吞吐量
max.poll.records = 500
# 首次启动从头消费历史数据
auto.offset.reset = "earliest"
# 自动提交offset,生产可根据业务改为手动提交
enable.auto.commit = "true"
}
}
}
transform {
# 第一层转换:JsonPath解析消息内content嵌套json字段
JsonPath {
plugin_input = "fuji"
plugin_output = "after_json_parse"
columns = [
{
src_field = "content"
path = "$.LineName"
dest_field = "LINENAME"
dest_type = "string"
},
{
src_field = "content"
path = "$.MachineName"
dest_field = "MACHINENAME"
dest_type = "string"
},
{
src_field = "content"
path = "$.ModuleNo"
dest_field = "MODULENO"
dest_type = "string"
},
{
src_field = "content"
path = "$.RobotNo"
dest_field = "ROBOTNO"
dest_type = "string"
},
{
src_field = "content"
path = "$.ModuleSerial"
dest_field = "MODULESERIAL"
dest_type = "string"
},
{
src_field = "content"
path = "$.HeadType"
dest_field = "HEADTYPE"
dest_type = "string"
},
{
src_field = "content"
path = "$.HeadSerial"
dest_field = "HEAFSERIAL"
dest_type = "string"
},
{
src_field = "content"
path = "$.UpdateTime"
dest_field = "UPDATETIME"
dest_type = "string"
},
# 原始完整json存入扩展字段
{
src_field = "content"
path = "$"
dest_field = "EXTJSON"
dest_type = "string"
}
]
}
# 第二层转换:SQL函数加工、生成主键、日期格式化
Sql {
plugin_input = "after_json_parse"
plugin_output = "result"
query = """
SELECT
UUID() AS ID,
LINENAME,
MACHINENAME,
MODULENO,
ROBOTNO,
MODULESERIAL,
HEADTYPE,
HEAFSERIAL,
-- 处理带T的ISO时间字符串,适配Oracle日期类型
TO_DATE(SUBSTR(UPDATETIME,0,19), 'yyyy-MM-dd''T''HH:mm:ss') AS UPDATETIME,
NOW() AS INSERTTIME,
EXTJSON
FROM after_json_parse
"""
}
}
sink {
jdbc {
plugin_input = "result"
# Oracle连接串
url = "jdbc:oracle:thin:xxx:1521:xx"
driver = "oracle.jdbc.OracleDriver"
username = "xxx"
password = "xxx"
table = "a"
# 自定义insert语句,字段顺序必须和SQL查询返回顺序严格一致
query = "INSERT INTO EMS.a(ID,LINENAME,MACHINENAME,MODULENO,ROBOTNO,MODULESERIAL,HEADTYPE,HEAFSERIAL,UPDATETIME,INSERTTIME,EXTJSON) VALUES(?,?,?,?,?,?,?,?,?,?,?)"
}
}
三、核心配置要点说明
1. Kafka JSON 消息解析:JsonPath src_field 关键配置
Kafka Source format = json 代表整条 kafka 消息体解析为 Json 对象,业务中实际业务字段全部嵌套在content节点下。
src_field = "content":指定从解析后的根 json 里取出 content 子对象,再基于这个子对象执行 JsonPath 路径$.LineName提取值;- 若不指定
src_field,默认从整条消息根节点匹配 path,嵌套结构会提取不到数据。
2. 双层 Transform 设计:JsonPath + SQL 分工
- JsonPath:只做 JSON 嵌套字段提取、字段重命名、类型统一;
- SQL Transform:负责复杂逻辑,包含:
- 生成全局唯一主键 UUID ();
- ISO 格式时间字符串转 Oracle Date 类型;
- 新增入库时间 INSERTTIME;
- 统一字段输出顺序,给 JDBC Sink 使用。 拆分后可读性更高,后续新增字段只需要同步修改两处,便于维护。
3. Oracle JDBC Sink 固定规范
- 驱动固定:
oracle.jdbc.OracleDriver,运行环境必须上传 ojdbc 驱动包到 seatunnel/lib; - 连接串标准格式:
jdbc:oracle:thin:@ip:1521:服务名; - 自定义 query 写入模式:不依赖框架自动生成 SQL,手写 Insert 语句适配多 schema 表(
EMS.a)
四、实操踩坑全记录(重点排错)
坑 1:Kafka 能正常消费消息,但 Oracle 无数据入库,无报错日志
现象
任务正常启动,监控看到 kafka offset 持续滚动(数据已经被消费),Oracle 表里无新增数据,控制台无异常堆栈。
根因
使用自定义query参数时,SeaTunnel JDBC Sink 底层仅做参数占位符填充,不会校验:
- SQL 查询输出字段数量 和 Insert 问号占位数量是否匹配;
- 字段顺序、字段类型和 Oracle 表字段是否对应; 顺序错位、字段数量不一致、类型不兼容不会抛出明显报错,直接丢弃本条数据。
排查步骤
- 打印中间流数据:临时增加 Console Sink 输出
result流,核对 SQL 查询输出字段顺序; - 逐个数 SELECT 字段数量、Insert 问号数量,保证 1:1 对应;
- 核对日期、字符串、UUID 等字段和 Oracle 表字段类型是否匹配。
坑 2:JsonPath 提取不到嵌套 JSON 字段,全部为空
根因
忘记配置src_field = "content",JsonPath 默认从 kafka 消息根节点匹配路径$.LineName,而业务真实字段都在 content 子节点内部。
解决
所有提取嵌套 content 内部字段的 JsonPath 规则,统一增加src_field = "content"。
坑 3:ISO 时间字符串2026-06-17T10:30:00写入 Oracle 日期报错
根因
直接将带 T 的字符串存入 Oracle Date 类型,隐式转换失败。
解决
SQL Transform 中截取前 19 位字符,使用 Oracle 兼容格式化模板转换日期:
sql
TO_DATE(SUBSTR(UPDATETIME,0,19), 'yyyy-MM-dd''T''HH:mm:ss') AS UPDATETIME
坑 4:Kafka 消费完数据直接丢失,不入库
双重排查方向:
- 字段顺序 / 数量不匹配(坑 1 场景),数据静默丢弃;
- offset 自动提交时机早于数据库写入完成:
- 当前配置
enable.auto.commit = "true",Kafka 消费者会定时提交 offset,若数据库写入延迟 / 失败,数据已经标记消费,丢失数据; - 生产优化:关闭自动提交,开启 JDBC 事务批量写入,写入成功后手动提交 offset。
- 当前配置
坑 5:UUID 主键插入 Oracle 报长度 / 格式异常
优化方案
- Oracle 主键字段设置为 VARCHAR2 (50),容纳完整 UUID 字符串;
- 若业务需要数字主键,可替换 SQL 函数
UUID()为雪花 ID 函数。
五、生产优化建议
- 并行度:调试用 1,线上根据 Kafka 消息吞吐量调整 parallelism;
- Offset 提交:生产环境关闭
enable.auto.commit,避免数据丢失; - 批量写入:JDBC Sink 增加 batch.size 参数,提升 Oracle 写入性能;
- 日志排查:开启 SeaTunnel DEBUG 日志,打印 Sink 插入前的数据,快速定位字段不匹配问题;
- 驱动依赖:部署时确认 ojdbc8 驱动放置在 lib 目录,否则会报驱动类找不到。