【实时数仓】动态分流的实现源码(反序列化器、配置表、广播流、业务流)

一 根据MySQL的配置表,动态进行分流

动态分流整体思路:

在这里插入图片描述

1 自定义反序列化器

(1)需求分析

使用FLinkCDC API方式获取到的内容如下

// 封装的数据对象类型
SourceRecord{
   
	sourcePartition={
   server=mysql_binlog_source}, 
	sourceOffset={
   file=mysql-bin.000004, pos=1343, row=1, snapshot=true}
} 
// ConnectRecord 是 SourceRecord的父类
ConnectRecord{
   
	topic='mysql_binlog_source.gmall2022_realtime.t_user', 
	kafkaPartition=null, 
	key=Struct{
   id=1}, 
	keySchema=Schema{
   mysql_binlog_source.gmall2022_realtime.t_user.Key:STRUCT},
value=Struct{
   
after=Struct{
   id=1,name=zhangsan,age=18},
source=Struct{
   version=1.4.1.Final,connector=mysql,name=mysql_binlog_source,ts_ms=0,snapshot=true,db=gmall2022_realtime,table=t_user,server_id=0,file=mysql-bin.000004,pos=1343,row=0},
op=c,ts_ms=1669896172346}, 
valueSchema=Schema{
   mysql_binlog_source.gmall2022_realtime.t_user.Envelope:STRUCT}, 
timestamp=null, 
headers=ConnectHeaders(headers=)}

自动定义反序列化器,实现将以上信息转化为JSON格式的字符串,包换的属性包括:数据库名称,表名,操作类型,影响的数据内容。

以上内容中有价值的信息如下:

ConnectRecord{
	value=Struct{
		after=Struct{id=1,name=zhangsan,age=18},
		source=Struct{
			db=gmall2022_realtime,
			table=t_user
		},
		op=c
	},
}		

(2)代码实现

/**
 * 通过FlinkCDC动态读取MySQL表中的数据 -- DataStreamAPI
 *
 * 自定义反序列化器
 */
public class FlinkCDC03_CustomerSchema {
   
    public static void main(String[] args) throws Exception {
   
        //TODO 1 准备流处理环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        //TODO 3 创建Flink-MySQL-CDC的Source
        Properties props = new Properties();
        props.setProperty("scan.startup.mode","initial");
        SourceFunction<String> sourceFunction = MySQLSource.<String>builder()
                .hostname("hadoop101")
                .port(3306)
                .username("root")
                .password("123456")
                // 可配置多个库
                .databaseList("gmall2022_realtime")
                ///可选配置项,如果不指定该参数,则会读取上一个配置中指定的数据库下的所有表的数据
                //注意:指定的时候需要使用"db.table"的方式
                .tableList("gmall2022_realtime.t_user")
                .debeziumProperties(props)
                .deserializer(new MySchema())
                .build();

        //TODO 4 使用CDC Source从MySQL读取数据
        DataStreamSource<String> mysqlDS = env.addSource(sourceFunction);

        //TODO 5 打印输出
        mysqlDS.print();

        //TODO 6 执行任务
        env.execute();
    }
}

class MySchema implements DebeziumDeserializationSchema<String> {
   

    /**
     * ConnectRecord{
     *     value=Struct{
     *        after=Struct{id=1,name=zhangsan,age=18},
     *        source=Struct{
     *           db=gmall2022_realtime,
     *           table=t_user
     *                },
     *        op=c
     *     },
     * }
     */
    // 反序列化
    @Override
    public void deserialize(SourceRecord sourceRecord, Collector<String> collector) throws Exception {
   
        // 导入的是org.apache.kafka.connnect.data包
        Struct valueStruct = (Struct) sourceRecord.value();
        // 获取数据的来源
        Struct afterStruct = valueStruct.getStruct("after");
        // 获取数据库和表名的来源
        Struct sourceStruct = valueStruct.getStruct("source");
        // 获取数据库
        String database = sourceStruct.getString("db");
        // 获取表名
        String table = sourceStruct.getString("table");
        // 获取操作类型
//        String op = valueStruct.getString("op");
        String type = Envelope.operationFor(sourceRecord).toString().toLowerCase();
        if(type.equals("create")){
   
            type = "insert";
        }
        JSONObject jsonObj = new JSONObject();
        jsonObj.put("database",database);
        jsonObj.put("table",table);
        jsonObj.put("type",type);
        // 获取影响的数据
        // 删除时,afterStruct为空
        JSONObject dataJsonObj = new JSONObject();
        if (afterStruct != null){
   
            // schema获取源数据的格式,fields获取里面的各个元素
            for (Field field : afterStruct.schema().fields()) {
   
                String fieldName = field.name();
                Object fieldValue = afterStruct.get(field);
                dataJsonObj.put(fieldName,fieldValue);
            }
        }
        // 删除操作会使得data属性不为空,但size为0
        jsonObj.put("data",dataJsonObj);

        // 向下游发送数据
        collector.collect(jsonObj.toJSONString()) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OneTenTwo76

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值