该博客仅针对Java客户端做了整理,其他语言看官网的多语言部分:https://github.com/alibaba/canal/wiki
一、引入Maven依赖
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.client</artifactId>
<version>1.1.0</version>
</dependency>
二、Java客户端
public class CanalClientTest {
/**
* Canal服务端IP
*/
private final static String SERVER_IP = "172.121.0.68";
/**
* Canal服务端监听的端口号
*/
private final static Integer SERVER_PORT = 11111;
/**
* 目标名称,对应服务端的实例名称,这里的example即conf/example实例
*/
private final static String DESTINATION = "example";
public static void main(String args[]) {
// 创建链接
CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress(SERVER_IP, SERVER_PORT), DESTINATION, "", "");
try{
// 接入连接
connector.connect();
/**
* Canal整合了MQTT,当且仅当Canal开启了MQTT主题订阅功能时,连接才需要订阅主题。如下表示订阅所有主题
* connector.subscribe(".*\\..*");
*/
// 心跳次数
int heart = 0;
while (true) {
// 单次获取指定数量的数据
Message message = connector.getWithoutAck(100);
// 本批次数据ID
long batchId = message.getId();
// 本批次数据量
int size = message.getEntries().size();
// 本批次是否有数据
if (batchId == -1 || size == 0) {
System.out.println("---------- heartbeat "+(heart++));
// 没有数据,则休眠1s之后继续获取
Thread.sleep(1000);
} else {
System.out.printf("=================================== message[batchId=%s, size=%s] \n", batchId, size);
// 数据处理
printEntry(message.getEntries());
}
/**
* 提交确认收到数据
* connector.ack(batchId);
* 处理失败, 回滚数据
* connector.rollback(batchId);
*/
}
} catch (Exception e){
e.printStackTrace();
System.out.println("============ program error. close connect!");
// 关闭连接
connector.disconnect();
}
}
private static void printEntry(List<CanalEntry.Entry> entrys) {
// 遍历每一组数据
for (CanalEntry.Entry entry : entrys) {
// 如果是事务开始或者事务结束类型数据则不作处理
if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN || entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND) {
System.out.println("============= ignore this type data.");
continue;
}
CanalEntry.RowChange rowChage = null;
try {
rowChage = CanalEntry.RowChange.parseFrom(entry.getStoreValue());
} catch (Exception e) {
e.printStackTrace();
continue;
}
CanalEntry.EventType eventType = rowChage.getEventType();
System.out.println("============ 操作类型:"+eventType+" 操作对象表:"+entry.getHeader().getSchemaName()+"."+entry.getHeader().getTableName());
for (CanalEntry.RowData rowData : rowChage.getRowDatasList()) {
if (eventType == EventType.DELETE) {
printColumn(rowData.getBeforeColumnsList());
} else if (eventType == EventType.INSERT) {
printColumn(rowData.getAfterColumnsList());
} else if (eventType == EventType.UPDATE) {
System.out.println("--------------------------- 修改前数据");
printColumn(rowData.getBeforeColumnsList());
System.out.println("--------------------------- 修改后数据");
printColumn(rowData.getAfterColumnsList());
}
}
}
}
private static void printColumn(List<CanalEntry.Column> columns) {
for (CanalEntry.Column column : columns) {
System.out.println(column.getName() + ":" + column.getValue() + " update=" + column.getUpdated());
}
}
}
三、Java客户端升级版
public class CanalClientTestSuper {
/**
* Canal服务端IP
*/
private final static String SERVER_IP = "172.121.0.68";
/**
* Canal服务端监听的端口号
*/
private final static Integer SERVER_PORT = 11111;
/**
* 目标名称,对应服务端的实例名称,这里的example即conf/example实例
*/
private final static String DESTINATION = "example";
public static void main(String[] args) {
// 创建链接
CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress(SERVER_IP, SERVER_PORT), DESTINATION, "", "");
try {
// 接入连接
connector.connect();
connector.rollback();
int heart = 0;
while (true) {
// 单次获取指定数量的数据
Message message = connector.getWithoutAck(100);
// 本批次数据ID
long batchId = message.getId();
// 本批次数据量
int size = message.getEntries().size();
// 本批次是否有数据
if (batchId == -1 || size == 0) {
System.out.println("---------- heartbeat " + (heart++));
// 没有数据,则休眠1s之后继续获取
Thread.sleep(1000);
} else {
System.out.printf("=================================== message[batchId=%s, size=%s] \n", batchId, size);
// 数据处理
dataHandle(message.getEntries());
}
connector.ack(batchId);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("============ program error. close connect!");
// 关闭连接
connector.disconnect();
}
}
/**
* 数据处理
*
* @param entrys
*/
private static void dataHandle(List<CanalEntry.Entry> entrys) {
for (CanalEntry.Entry entry : entrys) {
if (EntryType.ROWDATA == entry.getEntryType()) {
try {
RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
CanalEntry.EventType eventType = rowChange.getEventType();
if (eventType == EventType.DELETE) {
dealDeleteSql(entry);
} else if (eventType == EventType.UPDATE) {
dealUpdateSql(entry);
} else if (eventType == CanalEntry.EventType.INSERT) {
dealInsertSql(entry);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 解析更新语句
*
* @param entry
*/
private static void dealUpdateSql(CanalEntry.Entry entry) {
try {
RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
List<CanalEntry.RowData> rowDatasList = rowChange.getRowDatasList();
for (CanalEntry.RowData rowData : rowDatasList) {
List<Column> newColumnList = rowData.getAfterColumnsList();
StringBuffer sql = new StringBuffer("UPDATE " + entry.getHeader().getSchemaName() + "." + entry.getHeader().getTableName() + " SET ");
for (int i = 0; i < newColumnList.size(); i++) {
sql.append(" " + newColumnList.get(i).getName()
+ " = '" + newColumnList.get(i).getValue() + "'");
if (i != newColumnList.size() - 1) {
sql.append(",");
}
}
sql.append(" WHERE ");
List<Column> oldColumnList = rowData.getBeforeColumnsList();
for (Column column : oldColumnList) {
if (column.getIsKey()) {
// 暂时只支持单一主键
sql.append(column.getName() + "=" + column.getValue());
break;
}
}
System.out.println("[update sql] --> "+sql+"\n");
}
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
}
/**
* 解析删除语句
*
* @param entry
*/
private static void dealDeleteSql(CanalEntry.Entry entry) {
try {
RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
List<CanalEntry.RowData> rowDatasList = rowChange.getRowDatasList();
for (CanalEntry.RowData rowData : rowDatasList) {
List<Column> columnList = rowData.getBeforeColumnsList();
StringBuffer sql = new StringBuffer("DELETE FROM " + entry.getHeader().getSchemaName() + "." + entry.getHeader().getTableName() + " WHERE ");
for (Column column : columnList) {
if (column.getIsKey()) {
// 暂时只支持单一主键
sql.append(column.getName() + "=" + column.getValue());
break;
}
}
System.out.println("[delete sql] --> "+sql+"\n");
}
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
}
/**
* 解析插入语句
*
* @param entry
*/
private static void dealInsertSql(CanalEntry.Entry entry) {
try {
RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
List<CanalEntry.RowData> rowDatasList = rowChange.getRowDatasList();
for (CanalEntry.RowData rowData : rowDatasList) {
List<Column> columnList = rowData.getAfterColumnsList();
StringBuffer sql = new StringBuffer("INSERT INTO " + entry.getHeader().getSchemaName() + "." + entry.getHeader().getTableName() + " (");
for (int i = 0; i < columnList.size(); i++) {
sql.append(columnList.get(i).getName());
if (i != columnList.size() - 1) {
sql.append(",");
}
}
sql.append(") VALUES (");
for (int i = 0; i < columnList.size(); i++) {
sql.append("'" + columnList.get(i).getValue() + "'");
if (i != columnList.size() - 1) {
sql.append(",");
}
}
sql.append(")");
System.out.println("[insert sql] --> "+sql+"\n");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}