Flink CDC系列之:Kafka的Debezium JSON 结构定义类DebeziumJsonStruct

这是一个 Debezium JSON 结构定义类,使用枚举来定义 Debezium JSON 格式的字段结构和位置信息。

类概述

java 复制代码
public class DebeziumJsonStruct

这个类通过嵌套枚举定义了 Debezium JSON 格式的完整结构,包括字段名称和位置信息。

嵌套枚举详解
DebeziumStruct - 顶层结构

java 复制代码
enum DebeziumStruct {
    SCHEMA(0, "schema"),
    PAYLOAD(1, "payload");

作用:定义 Debezium JSON 的顶层结构字段。

字段说明:

  • SCHEMA(0, "schema"):表结构信息(位置0,字段名"schema")
  • PAYLOAD(1, "payload"):数据负载信息(位置1,字段名"payload")

对应的 JSON 结构:

java 复制代码
{
  "schema": { ... },    // SCHEMA 字段
  "payload": { ... }    // PAYLOAD 字段
}

DebeziumPayload - 数据负载结构

java 复制代码
enum DebeziumPayload {
    BEFORE(0, "before"),
    AFTER(1, "after"),
    OPERATION(2, "op"),
    SOURCE(3, "source");

作用:定义 payload 对象内部的字段结构。

字段说明:

  • BEFORE(0, "before"):变更前的数据(位置0,字段名"before")
  • AFTER(1, "after"):变更后的数据(位置1,字段名"after")
  • OPERATION(2, "op"):操作类型(位置2,字段名"op")
  • SOURCE(3, "source"):源数据库信息(位置3,字段名"source")

对应的 JSON 结构:

java 复制代码
{
  "payload": {
    "before": { ... },      // BEFORE 字段
    "after": { ... },       // AFTER 字段  
    "op": "c",             // OPERATION 字段
    "source": { ... }      // SOURCE 字段
  }
}

DebeziumSource - 源信息结构

java 复制代码
enum DebeziumSource {
    DATABASE(0, "db"),
    TABLE(1, "table");

作用:定义 source 对象内部的字段结构。

字段说明:

  • DATABASE(0, "db"):数据库名称(位置0,字段名"db")
  • TABLE(1, "table"):表名称(位置1,字段名"table")

对应的 JSON 结构:

java 复制代码
{
  "source": {
    "db": "inventory",     // DATABASE 字段
    "table": "users"       // TABLE 字段
  }
}

枚举设计特点

位置和名称双重映射

java 复制代码
private final int position;    // 位置索引
private final String fieldName; // 字段名称

优势:

  • 可以通过位置快速访问
  • 可以通过名称清晰标识

类型安全

使用枚举替代字符串常量,避免拼写错误:

java 复制代码
// 安全的方式
DebeziumPayload.BEFORE.getFieldName()  // 返回 "before"

// 不安全的方式(容易拼错)
String field = "befor";  // 拼写错误

易于扩展

添加新字段只需在对应枚举中添加新值:

java 复制代码
enum DebeziumPayload {
    // 现有字段...
    TIMESTAMP(4, "ts_ms"),      // 新增时间戳字段
    TRANSACTION(5, "transaction"); // 新增事务字段

实际使用场景

在序列化器中的使用

java 复制代码
public class DebeziumJsonSerializationSchema {
    
    public byte[] serialize(Event event) {
        // 构建 Debezium JSON 结构
        ObjectNode rootNode = objectMapper.createObjectNode();
        
        // 使用枚举确保字段名称一致
        rootNode.set(
            DebeziumStruct.SCHEMA.getFieldName(), 
            buildSchemaNode()
        );
        
        rootNode.set(
            DebeziumStruct.PAYLOAD.getFieldName(),
            buildPayloadNode(event)
        );
        
        return objectMapper.writeValueAsBytes(rootNode);
    }
    
    private ObjectNode buildPayloadNode(Event event) {
        ObjectNode payloadNode = objectMapper.createObjectNode();
        
        // 设置操作类型
        payloadNode.put(
            DebeziumPayload.OPERATION.getFieldName(),
            getOperationCode(event.op())
        );
        
        // 设置前后数据
        payloadNode.set(
            DebeziumPayload.BEFORE.getFieldName(),
            convertToJson(event.before())
        );
        
        payloadNode.set(
            DebeziumPayload.AFTER.getFieldName(), 
            convertToJson(event.after())
        );
        
        // 设置源信息
        payloadNode.set(
            DebeziumPayload.SOURCE.getFieldName(),
            buildSourceNode(event.tableId())
        );
        
        return payloadNode;
    }
    
    private ObjectNode buildSourceNode(TableId tableId) {
        ObjectNode sourceNode = objectMapper.createObjectNode();
        
        sourceNode.put(
            DebeziumSource.DATABASE.getFieldName(),
            tableId.getSchemaName()
        );
        
        sourceNode.put(
            DebeziumSource.TABLE.getFieldName(),
            tableId.getTableName()
        );
        
        return sourceNode;
    }
}

在反序列化器中的使用

java 复制代码
public class DebeziumJsonDeserializationSchema {
    
    public Event deserialize(byte[] message) {
        JsonNode rootNode = objectMapper.readTree(message);
        
        // 使用枚举字段名获取节点
        JsonNode payloadNode = rootNode.get(
            DebeziumStruct.PAYLOAD.getFieldName()
        );
        
        // 解析操作类型
        String operation = payloadNode.get(
            DebeziumPayload.OPERATION.getFieldName()
        ).asText();
        
        // 解析源信息
        JsonNode sourceNode = payloadNode.get(
            DebeziumPayload.SOURCE.getFieldName()
        );
        
        String database = sourceNode.get(
            DebeziumSource.DATABASE.getFieldName()
        ).asText();
        
        String table = sourceNode.get(
            DebeziumSource.TABLE.getFieldName()
        ).asText();
        
        // ... 其他解析逻辑
    }
}

生成的完整 JSON 示例

基于这个结构定义,会生成如下格式的 JSON:

java 复制代码
{
  "schema": {
    "type": "struct",
    "fields": [
      {
        "type": "struct",
        "fields": [
          {"type": "int32", "optional": false, "field": "id"},
          {"type": "string", "optional": true, "field": "name"}
        ],
        "optional": true,
        "name": "mysql-server-1.inventory.users.Value",
        "field": "before"
      }
    ],
    "optional": false,
    "name": "mysql-server-1.inventory.users.Envelope"
  },
  "payload": {
    "before": null,
    "after": {
      "id": 1001,
      "name": "张三"
    },
    "op": "c",
    "source": {
      "db": "inventory",
      "table": "users"
    }
  }
}

扩展建议

当前定义比较基础,实际 Debezium 格式包含更多字段,可以扩展为:

java 复制代码
enum DebeziumPayload {
    BEFORE(0, "before"),
    AFTER(1, "after"), 
    OPERATION(2, "op"),
    SOURCE(3, "source"),
    TIMESTAMP(4, "ts_ms"),
    TRANSACTION(5, "transaction");
}

enum DebeziumSource {
    DATABASE(0, "db"),
    TABLE(1, "table"),
    SERVER_ID(2, "server_id"),
    BINLOG_FILE(3, "file"),
    BINLOG_POSITION(4, "pos"),
    CONNECTOR(5, "connector"),
    SNAPSHOT(6, "snapshot");
}

总结:DebeziumJsonStruct 是一个结构定义类,它通过嵌套枚举:

✅ 定义标准结构:完整定义 Debezium JSON 格式的字段结构

✅ 提供类型安全:使用枚举替代字符串常量,避免拼写错误

✅ 支持双向访问:既可以通过名称访问,也可以通过位置访问

✅ 易于维护扩展:集中管理字段定义,支持轻松添加新字段

✅ 提高代码可读性:清晰的枚举名称使代码意图更明确

这个类是 Debezium JSON 序列化和反序列化组件的基础,确保了数据格式的规范性和一致性。

相关推荐
架构师老Y12 小时前
011、消息队列应用:RabbitMQ、Kafka与Celery
python·架构·kafka·rabbitmq·ruby
talen_hx29616 小时前
《kafka核心源码解读》学习笔记 Day 02
笔记·学习·kafka
lifallen16 小时前
如何保证 Kafka 的消息顺序性?
java·大数据·分布式·kafka
真实的菜16 小时前
Kafka 2.x vs 3.x,我为什么选择升级?
kafka
时光追逐者17 小时前
分享四款开源且实用的 Kafka 管理工具
分布式·kafka·开源
Rick199317 小时前
rabbitmq, rocketmq, kafka这三种消息如何分别保住可靠性,顺序性,以及应用场景?
kafka·rabbitmq·rocketmq
☞遠航☜19 小时前
kafka快速上手
分布式·kafka·linq
工具罗某人1 天前
docker compose部署kafka集群搭建
docker·容器·kafka
qq_297574672 天前
【Kafka 系列・入门第六篇】Kafka 集群部署(3 节点)+ 负载均衡配置
分布式·kafka·负载均衡