Apache Seatunnel 抽取SQL server实时同步到Oracle(四)

Apache Seatunnel 抽取SQL server实时同步到Oracle(四)

前面文档已经测试seatunnel可以正常抽取SQL server数据库表,接下来我们来配置SQL server到Oracle的实时同步。

链接: Apache seatunel配置-数据同步测试(直接把采集数据打印到控制面板) - SQL server

关键说明与前置条件:

要实现从 SQL Server 到 Oracle 的实时同步,需要将 Source 从批处理的 Jdbc 换成 CDC 连接器 SqlServer-CDC,并将 job.mode 改为 STREAMING。Sink 端则使用 Oracle JDBC 连接器。

  1. 驱动依赖

SQL Server CDC 需要 mssql-jdbc 驱动,Oracle Sink 需要 ojdbc8 驱动(以及可选的 orai18n.jar 用于中文字符集)。两者都需要放在 ${SEATUNNEL_HOME}/lib/ 目录下。

  1. SQL Server 端开启 CDC

实时同步的前提是源库和表已启用 CDC。需要在 SQL Server 上执行类似以下命令(需 sysadmin 权限):

复制代码
-- 对数据库启用 CDC
EXEC sys.sp_cdc_enable_db;

-- 对表 testtab 启用 CDC(需要 SQL Server Agent 运行)
EXEC sys.sp_cdc_enable_table
    @source_schema = N'dbo',
    @source_name   = N'testtab',
    @role_name     = NULL;
  1. 关于 table-names 格式

SQL Server CDC 的 table-names 要求使用 三段式:数据库名.schema名.表名,例如 AMDBdatabase.dbo.testtab。这一点与批处理 Jdbc Source 中只写 dbo.testtab 不同。

  1. Oracle Sink 的 database 与 table

Oracle 中表默认属于当前用户对应的模式(Schema)。如果你用 ogg_cdc 或专用用户连接 Oracle,database 填该用户对应的模式名即可。表名 TESTTAB 在 Oracle 中默认是大写(未加引号创建时),这里保持一致。

  1. 主键
    CDC 同步要求源表有主键,否则无法正确处理更新和删除事件。你的 testtab 已有 id 主键,符合要求。

调整conf配置文件

说明:目标不需要提前创建tab2表结构

如果存在则先删除

复制代码
SQL> drop table tab2 purge;

Table dropped.

cat .../config/demo_mssql_to_oracle.conf

复制代码
env {
  job.mode = "STREAMING"
  parallelism = 1
  # 实时作业需要 checkpoint 来保证断点续传和一致性
  checkpoint.interval = 10000
}

source {
  SqlServer-CDC {
    base-url = "jdbc:sqlserver://192.168.56.122:1433;databaseName=AMDBdatabase;encrypt=false"
    username = "ogg_cdc"
    password = "Bai_yun123"

    # 监控的数据库名,需要与 base-url 中的库名一致
    database-names = ["AMDBdatabase"]
    # 表名格式为:数据库名.schema名.表名
    table-names = ["AMDBdatabase.dbo.tab2"]

    # 启动模式:initial 表示先全量快照,再持续增量
    startup.mode = "initial"
  }
}

sink {
  Jdbc {
    driver = "oracle.jdbc.OracleDriver"
    # 请替换为你的 Oracle 实际地址、端口和服务名
    url = "jdbc:oracle:thin:@//192.168.56.123:1521/orcl"
    username = "amdb"
    password = "amdb"

    # 使用 database + table 让连接器自动生成写入 SQL
    generate_sink_sql = true
    database = "amdb"
    table = "TAB2"

    # 指定主键,CDC 的更新/删除操作依赖它
    primary_keys = ["id"]

    #表不存在时自动创建表结构
    schema_save_mode = "CREATE_SCHEMA_WHEN_NOT_EXIST"
    data_save_mode = "APPEND_DATA"

    # 写入批次与重试参数(按需调整)
    batch_size = 1000
    max_retries = 3
  }
}

启动同步进程

复制代码
--cluster方式启动任务

nohup /seatunnel_3.0/apache-seatunnel-3.0.0/bin/seatunnel.sh \
  --config /seatunnel_3.0/apache-seatunnel-3.0.0/config/demo_mssql_to_oracle.conf  \
  -m cluster \
  -cn seatunnel \
  -n sqlserver_to_oracle \
  > /seatunnel_3.0/apache-seatunnel-3.0.0/logs/demo_mssql_to_oracle.out 2>&1 &

[root@db1 bin]# nohup /seatunnel_3.0/apache-seatunnel-3.0.0/bin/seatunnel.sh   --config /seatunnel_3.0/apache-seatunnel-3.0.0/config/demo_mssql_to_oracle.conf    -m cluster   -cn seatunnel   -n sqlserver_to_oracle   > /seatunnel_3.0/apache-seatunnel-3.0.0/logs/demo_mssql_to_oracle.out 2>&1 &
[2] 12432
[root@db1 bin]# 

查看任务

/seatunnel_3.0/apache-seatunnel-3.0.0/bin/seatunnel.sh -l

复制代码
[root@db1 bin]# /seatunnel_3.0/apache-seatunnel-3.0.0/bin/seatunnel.sh -l
2026-10-19 06:35:22,461 INFO  [c.h.i.c.AbstractConfigLocator ] [main] - Loading configuration '/seatunnel_3.0/apache-seatunnel-3.0.0/config/seatunnel.yaml' from System property 'seatunnel.config'
2026-10-19 06:35:22,463 INFO  [c.h.i.c.AbstractConfigLocator ] [main] - Using configuration file at /seatunnel_3.0/apache-seatunnel-3.0.0/config/seatunnel.yaml
2026-10-19 06:35:22,465 INFO  [o.a.s.e.c.c.SeaTunnelConfig   ] [main] - seatunnel.home is /seatunnel_3.0/apache-seatunnel-3.0.0/bin
2026-10-19 06:35:22,547 INFO  [amlSeaTunnelDomConfigProcessor] [main] - Dynamic slot is enabled, the schedule strategy is set to REJECT
2026-10-19 06:35:22,547 INFO  [c.h.i.c.AbstractConfigLocator ] [main] - Loading configuration '/seatunnel_3.0/apache-seatunnel-3.0.0/config/hazelcast.yaml' from System property 'hazelcast.config'
2026-10-19 06:35:22,547 INFO  [c.h.i.c.AbstractConfigLocator ] [main] - Using configuration file at /seatunnel_3.0/apache-seatunnel-3.0.0/config/hazelcast.yaml
2026-10-19 06:35:22,846 INFO  [c.h.i.c.AbstractConfigLocator ] [main] - Loading configuration '/seatunnel_3.0/apache-seatunnel-3.0.0/config/hazelcast-client.yaml' from System property 'hazelcast.client.config'
2026-10-19 06:35:22,847 INFO  [c.h.i.c.AbstractConfigLocator ] [main] - Using configuration file at /seatunnel_3.0/apache-seatunnel-3.0.0/config/hazelcast-client.yaml
2026-10-19 06:35:23,083 INFO  [.c.i.s.ClientInvocationService] [main] - hz.client_1 [seatunnel] [5.1] Running with 2 response threads, dynamic=true
2026-10-19 06:35:23,129 INFO  [c.h.c.LifecycleService        ] [main] - hz.client_1 [seatunnel] [5.1] HazelcastClient 5.1 (20220228 - 21f20e7) is STARTING
2026-10-19 06:35:23,130 INFO  [c.h.c.LifecycleService        ] [main] - hz.client_1 [seatunnel] [5.1] HazelcastClient 5.1 (20220228 - 21f20e7) is STARTED
2026-10-19 06:35:23,155 INFO  [.c.i.c.ClientConnectionManager] [main] - hz.client_1 [seatunnel] [5.1] Trying to connect to cluster: seatunnel
2026-10-19 06:35:23,160 INFO  [.c.i.c.ClientConnectionManager] [main] - hz.client_1 [seatunnel] [5.1] Trying to connect to [localhost]:5801
2026-10-19 06:35:23,191 INFO  [c.h.c.LifecycleService        ] [main] - hz.client_1 [seatunnel] [5.1] HazelcastClient 5.1 (20220228 - 21f20e7) is CLIENT_CONNECTED
2026-10-19 06:35:23,191 INFO  [.c.i.c.ClientConnectionManager] [main] - hz.client_1 [seatunnel] [5.1] Authenticated with server [localhost]:5801:4c285204-6317-43f0-8aa4-cfea6cff782b, server version: 5.1, local address: /127.0.0.1:15875
2026-10-19 06:35:23,192 INFO  [c.h.i.d.Diagnostics           ] [main] - hz.client_1 [seatunnel] [5.1] Diagnostics disabled. To enable add -Dhazelcast.diagnostics.enabled=true to the JVM arguments.
2026-10-19 06:35:23,204 INFO  [c.h.c.i.s.ClientClusterService] [hz.client_1.event-3] - hz.client_1 [seatunnel] [5.1] 

Members [1] {
        Member [localhost]:5801 - 4c285204-6317-43f0-8aa4-cfea6cff782b [master node]
}

2026-10-19 06:35:23,240 INFO  [.c.i.s.ClientStatisticsService] [main] - Client statistics is enabled with period 5 seconds.
Job ID               Job Name       Job Status  Submit Time              Start Time               Finished Time            
-------------------  -------------  ----------  -----------------------  -----------------------  -----------------------  
1164512069689540609  SeaTunnel_Job  RUNNING     2026-10-19 06:35:13.747  2026-10-19 06:35:14.018  

2026-10-19 06:35:23,535 INFO  [c.h.c.LifecycleService        ] [main] - hz.client_1 [seatunnel] [5.1] HazelcastClient 5.1 (20220228 - 21f20e7) is SHUTTING_DOWN
2026-10-19 06:35:23,539 INFO  [.c.i.c.ClientConnectionManager] [main] - hz.client_1 [seatunnel] [5.1] Removed connection to endpoint: [localhost]:5801:4c285204-6317-43f0-8aa4-cfea6cff782b, connection: ClientConnection{alive=false, connectionId=1, channel=NioChannel{/127.0.0.1:15875->localhost/127.0.0.1:5801}, remoteAddress=[localhost]:5801, lastReadTime=2026-10-19 06:35:23.423, lastWriteTime=2026-10-19 06:35:23.364, closedTime=2026-10-19 06:35:23.536, connected server version=5.1}
2026-10-19 06:35:23,539 INFO  [c.h.c.LifecycleService        ] [main] - hz.client_1 [seatunnel] [5.1] HazelcastClient 5.1 (20220228 - 21f20e7) is CLIENT_DISCONNECTED
2026-10-19 06:35:23,545 INFO  [c.h.c.LifecycleService        ] [main] - hz.client_1 [seatunnel] [5.1] HazelcastClient 5.1 (20220228 - 21f20e7) is SHUTDOWN
2026-10-19 06:35:23,547 INFO  [.s.a.m.MetadataProviderManager] [main] - MetadataProvider closed
2026-10-19 06:35:23,547 INFO  [s.c.s.s.c.ClientExecuteCommand] [main] - Closed SeaTunnel client......
[root@db1 bin]# 
[root@db1 bin]# 

取消任务

复制代码
/seatunnel_3.0/apache-seatunnel-3.0.0/bin/seatunnel.sh \
  -can 1164512069689540609 \
  -cn seatunnel

暂停一个任务

复制代码
/seatunnel_3.0/apache-seatunnel-3.0.0/bin/seatunnel.sh -s 1164512069689540609

恢复任务

复制代码
/seatunnel_3.0/apache-seatunnel-3.0.0/bin/seatunnel.sh \
  -c /seatunnel_3.0/apache-seatunnel-3.0.0/config/demo_2tables_mysql.conf \
  -r 1164512069689540609 \
  -m cluster
  -cn seatunnel \
  -n sqlserver_to_oracle \
  > /seatunnel_3.0/apache-seatunnel-3.0.0/logs/demo_mssql_to_oracle.out 2>&1 &

DML测试

源端插入数据

目标端查看数据没有正常同步。经过AI分析,在源端:强制刷新并验证 后数据同步到目标库

--强制扫描

EXEC sys.sp_cdc_scan @maxtrans = 500, @maxscans = 10, @continuous = 1;

--在 SQL Server 中执行以下命令,查看捕获作业的状态:

EXEC sys.sp_cdc_help_jobs;

执行 EXEC sys.sp_cdc_help_jobs; 却返回了空结果集。

这说明 SQL Server 的 CDC 机制存在一个很关键的配置漏洞:数据库和表的 CDC 虽然已经启用,但底层的 CDC 捕获作业(Capture Job)根本没有运行,或者不存在。

为什么这是致命问题?

SQL Server 的 CDC 捕获机制依赖 SQL Server Agent 运行两个后台作业(cdc.你的数据库名_capture 和 cdc.你的数据库名_cleanup)。如果没有这个 capture 作业,事务日志中发生的变更就不会被写入 cdc.dbo_tab2_CT 表。SeaTunnel 读取不到 _CT 表的新记录,自然也就无法同步到 Oracle。这也就解释了为什么之前的截图里 cdc.dbo_tab2_CT 的最新记录时间停留在几个小时前,而你刚才插入的数据完全没有出现在里面。

系统通常会自动创建:按照 SQL Server 的默认机制,在数据库中为第一张表启用 CDC 时,系统会自动创建 cleanup 作业和 capture 作业。只有在作业被显式删除后,才需要用 sp_cdc_add_job 手动重建。

cleanup 不影响数据同步:cleanup 作业的唯一作用是根据保留策略(默认 72 小时)定期删除 _CT 变更表中的过期历史记录。它既不扫描事务日志,也不往 _CT 表里写新数据。SeaTunnel 读取数据靠的是 capture 作业,而不是 cleanup 作业

启用后系统自动生成内容

启用表 CDC 后 SQL Server 会自动生成:

CDC 捕获作业:cdc._capture

CDC 清理作业:cdc._cleanup

更改表:如 cdc.dbo_YourTable_CT

修复步骤

  1. 手动添加 CDC 捕获作业
    既然作业不存在,可以直接在 SQL Server 中执行命令来创建它。请在你的 AMDBdatabase 库上下文中执行以下语句:

USE AMDBdatabase;

GO

EXEC sys.sp_cdc_add_job @job_type = N'capture';

GO

再次运行EXEC sys.sp_cdc_help_jobs;,可以查询到记录了。

但是插入数据仍然没有自动同步到目标端。

强制重启 Capture 作业

USE AMDBdatabase;

GO

EXEC sys.sp_cdc_stop_job @job_type = N'capture';

EXEC sys.sp_cdc_start_job @job_type = N'capture';

执行完这两句后,绝对不要再去手动运行 sp_cdc_scan。

再次插入数据,可以正常自动同步了。

目标端

源端更新测试

目标端查询

源端删除测试

目标端查询

至此数据验证同步正常。

相关推荐
l1t1 小时前
DeepSeek总结的PostgreSQL 的 MVCC 很糟。其他所有的也一样。第1部分
数据库·postgresql
川石课堂软件测试1 小时前
JMeter异步接口测试实战
数据库·python·jmeter·mysql·kubernetes·测试用例·prometheus
下页、再停留1 小时前
【C#桌面客户端系列学习-14】SQLite数据库之增删改查完整示例
数据库·sqlite
她的男孩1 小时前
JAR 全对仍 checksum mismatch:Forge Admin 把 Flyway 从 filesystem 改成 classpath
java·数据库·spring boot
小马不起床1 小时前
Django 后端实战指南_16:动作分类、动作库、动作收藏查询接口
数据库·python·django
ycydynq1 小时前
django搜索功能
数据库·python·django
呆萌很1 小时前
DISTINCT 和 GROUP BY 核心区别
数据库·sql
小蒜学长1 小时前
基于数据挖掘的京东商城商品推荐系统设计与实现(代码+数据库+LW)
java·数据库·spring boot·后端·推荐系统·个性化推荐
小小AK1 小时前
金蝶其他入库到MES送检签收:库存同步策略实战教程
数据库·制造