文章目录
一 根据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())