当多表数据涌入,Apache SeaTunnel 如何巧妙化解主键冲突?

点亮Star!https://github.com/apache/seatunnel

来源 | 数仓生态圈

概述

当有多个数据库中的一张表具有类似的数据,例如有多个不同的系统来源,数据插入不同数据库中的表。此时,若需要把这些表数据汇总成一张表进行统计分析,会面临一个棘手问题:由于多张表具有相同的主键,直接汇总到一起会出现主键重复。而 Apache SeaTunnel 就能巧妙应对这一挑战。本篇文章将详细阐述 Apache SeaTunnel 是如何解决此问题的。

设计思想

本方案旨在将分布在两个独立MySQL数据库(datasource1和datasource2)中的test表,实时、准确地同步汇总到第三个数据库(datasource3)的test表中。为实现实时同步与数据修改的捕获,采用基于MySQL二进制日志(Binlog)的变更数据捕获(CDC)技术。为解决源表自增主键ID可能重复的问题,目标表将引入"数据来源"字段,并与原ID组成联合主键,确保数据的唯一性与可追溯性。

工具准备

1、Mysql5.7

2、SeaTunnel2.3.12

MySQL配置检查

Mysql是否开启binlog

复制代码
mysql> show variables where variable_name in ('log_bin', 'binlog_format', 'binlog_row_image', 'gtid_mode', 'enforce_gtid_consistency');+--------------------------+-------+| Variable_name            | Value |+--------------------------+-------+| binlog_format            | ROW   || binlog_row_image         | FULL  || enforce_gtid_consistency | OFF   || gtid_mode                | OFF   || log_bin                  | ON    |+--------------------------+-------+

如果log_bin的值不是ON, 配置Mysql配置文件mysql.cnf。

复制代码
log-bin=mysql-binserver-id=1binlog_format=ROWbinlog_checksum=NONE

重启Mysql服务

SeaTunnel配置

1、安装连接器

${SEATUNNEL_HOME}/config/plugin_config文件,增加connector-cdc-mysqlconnector-jdbc

安装连接器

复制代码
sh bin/install-plugin.sh

2、安装 MySQL 驱动

我是用的是mysql-connector-java-8.0.28.jar

把jar包放到${SEATUNNEL_HOME}/lib/目录下

准备数据

复制代码
CREATE DATABASE source1CHARACTER SET utf8mb4;CREATE DATABASE source2CHARACTER SET utf8mb4;CREATE DATABASE source3CHARACTER SET utf8mb4;use source1;CREATE TABLE `test`  (  `id` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(50) CHARACTER SET utf8mb4,  PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 ;
insert into test values(1,'张三');insert into test values(2,'李四');
use source2;CREATE TABLE `test`  (  `id` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(50) CHARACTER SET utf8mb4,  PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 ;
insert into test values(1,'王五');insert into test values(2,'赵六');
use source3;CREATE TABLE `test`  (  `id` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(50) CHARACTER SET utf8mb4,  `sources` varchar(50) CHARACTER SET utf8mb4,  PRIMARY KEY (`id`, `sources`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 ;

准备脚本

复制代码
env {  parallelism = 2  job.mode = "STREAMING"  checkpoint.interval = 20000}
source {  MySQL-CDC {    plugin_output = "source_data1"    url = "jdbc:mysql://10.0.12.100:3306/source1"    username = "root"    password = "root"    table-names = ["source1.test"]    startup.mode = initial      }  MySQL-CDC {    plugin_output = "source_data2"    url = "jdbc:mysql://10.0.12.100:3306/source2"    username = "root"    password = "root"    table-names = ["source2.test"]    startup.mode = initial      }}transform {  Sql {    plugin_input = "source_data1"    plugin_output = "result1"    query = "SELECT *, 'source1' AS sources FROM source_data1"  }  Sql {    plugin_input = "source_data2"      plugin_output = "result2"    query = "SELECT *, 'source2' AS sources FROM source_data2"  }}sink {  Jdbc {    plugin_input = ["result1","result2"]    url = "jdbc:mysql://10.0.12.100:3306/source3"    driver = "com.mysql.cj.jdbc.Driver"    username = "root"    password = "root"    database = "source3"    table = "test"    generate_sink_sql = true    primary_keys = ["id","sources"]     }}

这里使用了一个配置来同步2个库,当然也可以配置成2个任务进行同步。

这里使用2个source,一个source_data1,一个source_data2。

transform也使用2个Sql,进行处理对应的2个

source。这里写成固定值来读取sources。

sink对应上面的2个Sql,输出表test,这里设置主键用于修改。

这里目标表需要手动创建,否则提示下面错误

复制代码
BLOB/TEXT column 'sources' used in key specification without a key length

测试

1、启动

复制代码
bin/seatunnel.sh --config job/mysql_mysql.conf -m local

2、查看数据

复制代码
mysql> select * from test;+----+--------+---------+| id | name   | sources |+----+--------+---------+|  1 | 张三   | source1 ||  1 | 王五   | source2 ||  2 | 李四   | source1 ||  2 | 赵六   | source2 |+----+--------+---------+

3、修改数据

复制代码
use source1;insert into test values(3,'钱七');update test set name='张三1' where id=1;use source2;delete from test where id=1;

4、查询数据

复制代码
mysql> select * from test;+----+---------+---------+| id | name    | sources |+----+---------+---------+|  1 | 张三1   | source1 ||  2 | 李四    | source1 ||  2 | 赵六    | source2 ||  3 | 钱七    | source1 |+----+---------+---------+

总结

以上操作就是把2个库中的表数据同步到另一个库中的一张表的所有过程,我有看到其他文章可以自动创建输出表,但一直没有测试出来,有测试出来的朋友可以留言相告。

相关推荐
稀土熊猫君1 小时前
一个人能做出什么开源项目?
vue.js·后端·开源
狂师6 小时前
比 Playwright 更给力,推荐一个AI Agent的浏览器自动化开源项目!
前端·开源·测试
AI袋鼠帝8 小时前
开源「仓颉.Skill」2.0,你现在可以蒸馏任何视频!
开源·aigc
冬奇Lab19 小时前
每日一个开源项目(第146篇):openpilot - 开源自动驾驶辅助系统,曾在 Consumer Reports 评测中超过特斯拉 Autopilot
人工智能·开源·自动驾驶
她的男孩1 天前
后台接口加密别只会 HTTPS,ForgeAdmin 的 RSA + SM4/AES 源码拆解
后端·面试·开源
fthux1 天前
如果你用 Mac,那你可能需要 Noti Shift
macos·开源·github
冬奇Lab2 天前
每日一个开源项目(第145篇):Trellis - 把项目记忆、规范和任务上下文持久化进代码仓库
人工智能·开源·资讯
小爷毛毛_卓寿杰2 天前
我把一个 3B 模型塞进了 Xinference,然后它干掉了 DeepSeek V3.2
人工智能·开源·github