大数据:canal:Message数据格式和解析

 1.Message类:主要是id 和entries,rawEntries和raw(默认true)一般不去管这俩

  • public class Message implements Serializable {
        private static final long serialVersionUID = 1234034768477580009L;
        private long id;
        private List<Entry> entries = new ArrayList();
        private boolean raw = true;
        private List<ByteString> rawEntries = new ArrayList();
    
        //剩余是两个构造方法和setter/getter toString
    }
  • message{id,Entry ,rawEntries,raw(默认true)}  大体这么个关系(手工画图) 

Entry内部格式(entries子对象,entries的size和batchsize timeout有关)

  • 1.Header
    	version         [协议的版本号,default = 1]
    	logfileName     [binlog文件名]
    	logfileOffset   [binlog position]
    	serverId        [服务端serverId]
    	serverenCode    [变更数据的编码]
    	executeTime     [变更数据的执行时间]
    	sourceType      [变更数据的来源,default = MYSQL]
    	schemaName      [变更数据的schemaname]
    	tableName       [变更数据的tablename]
    	eventLength     [每个event的长度]
    	eventType       [insert/update/delete类型,default = UPDATE]
    	gtid            [当前事务的gitd]
    2.entryType         [事务头BEGIN/事务尾END/数据ROWDATA/HEARTBEAT/GTIDLOG]
    3.storeValue        [byte数据,可展开,对应的类型为RowChange]    
    	(RowChange)
    	  tableId             [tableId,由数据库产生]
    	  eventType           [数据变更类型,default = UPDATE]
    	  isDdl               [标识是否是ddl语句,比如create table/drop table]
    	  sql                 [ddl/query的sql语句]
    	  ddlSchemaName       [ddl/query的schemaName,会存在跨库ddl,需要保留执行ddl的当前schemaName]
    	  3.1rowDatas         [具体insert/update/delete的变更数据,可为多条,1个binlog event事件可对应多条变更,比如批处理]
    			beforeColumns   [字段信息,增量数据(修改前,删除前),Column类型的数组]
    			afterColumns    [字段信息,增量数据(修改后,新增后),Column类型的数组] 	
    			  (Column)
    				index          [字段下标]      
    				sqlType        [jdbc type]
    				name           [字段名称(忽略大小写),在mysql中是没有的]
    				isKey          [是否为主键]
    				updated        [是否发生过变更]
    				isNull         [值是否为null]
    				value          [字段值,timestamp,Datetime是一个时间格式的文本]
    				length         [对应数据对象原始长度]
    				mysqlType      [字段mysql类型]
    

2.Message获取和简单解析

解析方法流程

  • connector.connect()          获取连接		 
    connector.subscribe          订阅	
    connector.getWithoutAck()    获取数据
        ---解析操作   业务处理 ----
    connector.ack()              提交确认
    connector.rollback()         回滚操作	
    connector.disconnect()       断开连接 

pom依赖

  •         <!-- https://mvnrepository.com/artifact/com.alibaba.otter/canal.common -->
            <dependency>
                <groupId>com.alibaba.otter</groupId>
                <artifactId>canal.client</artifactId>
                <version>1.1.1</version>
            </dependency>

简单解析主类

  • public class MessageParseSimple {
    
        // Canal 服务器地址
        private static final String SERVER_ADDRESS = "192.168.8.88";
        // Canal 端口 默认 11111
        private static final Integer PORT = 11111;
        // Canal 目的地即 canal 配置实例
        private static final String DESTINATION = "example";
        // Canal 用户名密码 默认为空
        private static final String USERNAME = "";
        private static final String PASSWORD = "";
    
        public static void main(String[] args) throws InvalidProtocolBufferException {
            final CanalConnector canalConnector = CanalConnectors.newSingleConnector(
                    new InetSocketAddress(SERVER_ADDRESS, PORT),
                    DESTINATION, USERNAME, PASSWORD);
            //建立连接
            canalConnector.connect();
            // 订阅
            canalConnector.subscribe(".*\\..*");
            //回滚到之前同步的那一个位置
            canalConnector.rollback();
            while (true) {
                // 获取数据但是不做确认,尽可能1000条
                final Message message = canalConnector.getWithoutAck(1000);
                //获取数据但是不做确认,尽可能1000条或者超时返回
                // final Message message = canalConnector.getWithoutAck(1000,100L, TimeUnit.MILLISECONDS);
                parseMessage(message);
            }
    
        }
    
        public static void parseMessage(Message message) throws InvalidProtocolBufferException {
            List<CanalEntry.Entry> entries = message.getEntries();
            List<ByteString> rawEntries = new ArrayList();
            System.out.println(rawEntries.toString());
            while (message.getId() != -1) {
                for (CanalEntry.Entry entry : entries) {
                    //得到header,详细取值可用get方法
                    CanalEntry.Header header = entry.getHeader();
                    System.out.println("----------------header---开始---------");
                    System.out.println(header.toString());
                    System.out.println("----------------header---结束---------");
    
                    //得到entrytype,详细取值可用get方法
                    CanalEntry.EntryType entryType = entry.getEntryType();
                    System.out.println("entrytype=" + entryType);
    
                    //获取storevalue-->rowchage格式
                    ByteString storeValue = entry.getStoreValue();
                    System.out.println(storeValue.toString());
                    CanalEntry.RowChange rowChage = CanalEntry.RowChange.parseFrom(entry.getStoreValue());
    
                    //解析rowchange中的rowdata
                    List<CanalEntry.RowData> rowDatas = rowChage.getRowDatasList();
                    for (CanalEntry.RowData rowData : rowDatas) {
                        List<CanalEntry.Column> afterColumns = rowData.getAfterColumnsList();//用于非delete操作
                        List<CanalEntry.Column> beforeColumns = rowData.getBeforeColumnsList();//用于delete操作
                        for (CanalEntry.Column beforeColumn : beforeColumns) {
                            System.out.println("----------------before---开始---------");
                            System.out.println(beforeColumn.toString());
                            System.out.println("----------------before---结束---------");
                        }
                        for (CanalEntry.Column afterColumn : afterColumns) {
                            System.out.println("----------------after---开始---------");
                            System.out.println(afterColumn.toString());
                            System.out.println("----------------after---结束---------");
                        }
                    }
                    System.out.println("---------------------------------------------");
                }
            }
        }
    }

 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 可以回答这个问题。canal中间件可以实现redis和mysql的数据同步,它可以监控mysql数据库的binlog日志,将数据变更同步到redis中。同时,canal也支持将mysql数据同步到其他数据库,如elasticsearch等。 ### 回答2: Canal中间件是一种用于实现数据库数据同步的工具。它可以实现Redis和MySQL之间的数据同步。 首先,我们需要设置Canal中间件与Redis和MySQL的连接。通过配置Canal中间件的连接参数,使其能够连接到Redis和MySQL数据库。可以设置监控的表和字段,以确定需要同步的数据范围。 当MySQL数据库中的数据发生变化时,Canal中间件会自动捕获这些变化并生成相应的Binlog日志。通过监听MySQL数据库的Binlog日志,Canal中间件能够实时获取更新的数据。 接下来,Canal中间件将获取到的数据进行处理,将变化的数据转换成Redis可以接受的数据格式,并将其写入到Redis数据库中。这样就实现了MySQL中数据变化的同步到Redis数据库的功能。 通过Canal中间件,我们可以实现MySQL和Redis之间的双向数据同步。当MySQL中的数据发生改变时,Canal中间件会将变化的数据同步到Redis数据库中。同样地,当Redis中的数据发生改变时,Canal中间件也能够捕获这些变化并同步到MySQL数据库中。 这种数据同步的方式可以提高应用程序的性能和可靠性。通过将热点数据存储到Redis中,可以提高读取性能。同时,由于Canal中间件的实时同步机制,可以保证数据的一致性。 总结起来,Canal中间件可以实现Redis和MySQL之间的数据同步。它通过捕获MySQL数据库的Binlog日志,并将变化的数据转换成Redis可以接受的格式,实现了数据的同步。这种方式可以提高应用程序的性能和可靠性。 ### 回答3: Canal中间件是一个开源的数据同步工具,用于将数据库中的数据同步到其他数据源。在实现Redis和MySQL数据同步的场景下,可以通过以下步骤实现数据的同步: 第一步,安装配置Canal中间件。首先需要在服务器上安装Canal中间件,并配置Canal的相关参数,如数据源的地址、端口号、用户名和密码等。 第二步,配置Canal中间件连接MySQL数据库。需要在Canal配置文件中添加MySQL数据源的相关信息,包括MySQL服务器的地址、端口号、用户名和密码等。 第三步,配置Canal中间件连接Redis数据库。同样需要在Canal配置文件中添加Redis数据源的相关信息,包括Redis服务器的地址、端口号、密码等。 第四步,创建数据库表数据的监听和同步。通过创建Canal的实例,并指定需要监听的数据库和表,可以实现对特定表数据的监听和同步。 第五步,通过Canal中间件将MySQL数据同步到Redis。当MySQL数据库中的数据发生变化时,Canal中间件会将变更的数据解析并转发给Redis数据库,实现数据的同步。 通过以上步骤,即可实现Redis和MySQL数据的同步。Canal中间件作为数据同步的桥梁,能够实时监听MySQL数据库的变化,并将变更的数据同步到Redis,确保数据的一致性和及时性。 需要注意的是,在配置Canal中间件时,需要确保Canal和MySQL、Redis之间的网络连接正常,并且对应的用户有足够的权限来进行数据操作。同时,还需要进行相关的性能测试和优化,以确保数据同步的效率和稳定性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值