Canal 數據監控的使用
環境:
Docker: 19 版本
Java: 11 版本
MySQL: 8 版本
Canal: 1.1.+ 版本
1. MySQL 設置
1.1 開啓 binlog
修改 my.cnf 文件
正常在/etc/mysql/my.cnf
添加下面的內容.
# binlog setting
log-bin=/root/binlog/mysql-bin
server-id=13306
注: 如果使用了共享卷需要進行授權
chmod -R 777 <mysql-bin 文件所在的主機路徑>
重啓容器
查看 binlog 的狀態
SHOW VARIABLES LIKE 'log_bin%'
binlog 有三種格式, 默認是 ROW
SHOW VARIABLES LIKE 'binlog_format'
1.2 使用 root 賬號創建用戶並授予權限
create user canal@'%' IDENTIFIED by 'canal';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT, SUPER ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;
2. Docker 安裝 canal-server
運行容器並進入
dokcer pull canal/canal-server
docker run -d -it -p 11111:11111 --name=canal canal/canal-server
docker exec -it canal /bin/bash
修改文件
vi canal-server/conf/canal.properties
vi canal-server/conf/example/instance.properties
.*
代表所有的數據庫或者表
.*\\..*
中兩個.*
中間夾了一個\\.
而\\.
是用於轉義.
的。 第一個.*
代表所有的數據庫 第二個.*
代表所有的表
.*\\..*
==>所有的數據庫.所有的表
# 重啓
docker restart canal
3. Java 實現 Canal Client
需要建立一個 SpringBoot 形成將其形成 Jar. 方便使用.
https://www.bilibili.com/video/BV1GE411G7Hg?p=93
這個視頻下面的評論中的連接就有
導包
<dependency>
<groupId>com.ykenan.ykenan</groupId>
<artifactId>commerce_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- canal.client -->
<!--<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.client</artifactId>
<version>1.1.3</version>
</dependency>-->
<!-- 項目 canal.client jar 包 -->
<dependency>
<groupId>com.ykenan.ykenan</groupId>
<artifactId>commerce_canal</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
application.yml 配置文件
文件中的example
就是上邊設置canal.destinations
保持一致, 默認就是 example.
# canal client 配置
canal:
client:
instances:
example:
host: 192.168.19.129
port: 11111
userName: canal
password: canal
啓動類 加上
@EnableCanalClient
註解
監聽類
package com.commerce.canal.listener;
import com.alibaba.otter.canal.protocol.CanalEntry;
import com.ykenan.ykenan.annotation.CanalEventListener;
import com.ykenan.ykenan.annotation.DeleteListenPoint;
import com.ykenan.ykenan.annotation.InsertListenPoint;
import com.ykenan.ykenan.annotation.UpdateListenPoint;
import java.util.List;
/**
* 實現 MySQL 數據監聽
*/
@CanalEventListener
public class CanalDataEventListener {
/**
* 增加監聽
*
* @param eventType 當前操作的類型 (例如:增加數據)
* @param rowData 發生變更的一行數據
*/
@InsertListenPoint
public void onEventInsert(CanalEntry.EventType eventType, CanalEntry.RowData rowData) {
List<CanalEntry.Column> afterColumnsList = rowData.getAfterColumnsList();
System.out.println("增加後的數據:");
for (CanalEntry.Column column : afterColumnsList) {
// 列名
String name = column.getName();
// 變更後的數據
String value = column.getValue();
System.out.println(name + ":" + value);
}
}
/**
* 修改監聽
*
* @param eventType 當前操作的類型 (例如:增加數據)
* @param rowData 發生變更的一行數據
*/
@UpdateListenPoint
public void onEventUpdate(CanalEntry.EventType eventType, CanalEntry.RowData rowData) {
List<CanalEntry.Column> beforeColumnsList = rowData.getBeforeColumnsList();
System.out.println("修改前的數據:");
for (CanalEntry.Column column : beforeColumnsList) {
System.out.println(column.getName() + ":" + column.getValue());
}
System.out.println("修改後的數據:");
List<CanalEntry.Column> afterColumnsList = rowData.getAfterColumnsList();
for (CanalEntry.Column column : afterColumnsList) {
System.out.println(column.getName() + ":" + column.getValue());
}
}
/**
* 刪除監聽
*
* @param eventType 當前操作的類型 (例如:增加數據)
* @param rowData 發生變更的一行數據
*/
@DeleteListenPoint
public void onEventDelete(CanalEntry.EventType eventType, CanalEntry.RowData rowData) {
List<CanalEntry.Column> beforeColumnsList = rowData.getBeforeColumnsList();
System.out.println("刪除前的數據:");
for (CanalEntry.Column column : beforeColumnsList) {
System.out.println(column.getName() + ":" + column.getValue());
}
}
}
效果
監聽類中將上面的合在一個自定義中
/**
* 自定義監聽
*
* @param eventType 當前操作的類型 (例如:增加數據)
* @param rowData 發生變更的一行數據
*/
@ListenPoint(
// 指定監聽的類型
eventType = {CanalEntry.EventType.DELETE, CanalEntry.EventType.UPDATE, CanalEntry.EventType.INSERT,},
// 指定監聽的數據庫
schema = {"commerce_ad"},
// 指定監聽的表
table = {"tb_ad"},
// 指定實例的地址
destination = "example"
)
public void onEvent(CanalEntry.EventType eventType, CanalEntry.RowData rowData) {
List<CanalEntry.Column> beforeColumnsList = rowData.getBeforeColumnsList();
System.out.println("自定義操作前的數據:");
for (CanalEntry.Column column : beforeColumnsList) {
System.out.println(column.getName() + ":" + column.getValue());
}
System.out.println("自定義操作操作後的數據:");
List<CanalEntry.Column> afterColumnsList = rowData.getAfterColumnsList();
for (CanalEntry.Column column : afterColumnsList) {
System.out.println(column.getName() + ":" + column.getValue());
}
}
效果是一樣的