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("---------------------------------------------"); } } } }