使用canal订阅mysql的binlog,springboot使用canal订阅mysql的binlog
原创
©著作权归作者所有:来自51CTO博客作者秃了也弱了的原创作品,请联系作者获取转载授权,否则将追究法律责任
文章目录
写在前面
本文用到了docker,安装docker请移步:centos7安装docker-简单而详细无坑
一、初始化mysql
1、安装mysql
docker安装mysql-简单无坑
2、创建数据库
在这里创建了一个名为【mytest】的数据库。
3、修改mysql配置文件
修改my.cnf(默认在/etc/mysql目录),添加以下两行
server_id=1
#开启二进制
log-bin=mysql-bin
#表示需要同步的库
binlog-do-db=mytest
改完记得重启mysql。(/mysql/data目录下会出现mysql-bin.000001)
4、创建一个同步用户
在mysql中创建一个专门用来同步的用户
create user canal@'%' IDENTIFIED by 'canal';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT,SUPER ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;
5、查看主库的状态
二、初始化canal
1、创建网络,让mysql与canal通信
1、使用docker启动canal
# 下载canal
docker pull canal/canal-server:v1.1.5
# 启动canal
docker run -p 11111:11111 --name canal --network cxf -d canal/canal-server:v1.1.5
2、查看mysql地址
3、修改canal配置文件
修改canal.properties配置文件(/home/admin/canal-server/conf目录)(不需要改)
# 默认端口 11111
# 默认输出model为tcp, mysql就使用tcp
# tcp, kafka, RocketMQ
canal.serverMode = tcp
#################################################
######### destinations #############
#################################################
# canal可以有多个instance,每个实例有独立的配置文件,默认只 有一个example实例。
# 如果需要处理多个mysql数据的话,可以复制出多个example,对其重新命名,
# 命令和配置文件中指定的名称一致。然后修改canal.properties 中的 canal.destinations
# canal.destinations=实例 1,实例 2,实例 3
canal.destinations =
修改instance.properties配置文件(/home/admin/canal-server/conf/example目录)(只需要修改mysql地址即可)
# 不能和mysql重复
canal.instance.mysql.slaveId=2
# 使用mysql的虚拟ip和端口
canal.instance.master.address=172.17.0.3:3306
# 使用已创建的canal用户
canal.instance.dbUsername=canal
canal.instance.dbPassword=canal
canal.instance.connectionCharset = UTF-8
# canal.instance.defaultDatabaseName =test
# 表示匹配所有的库所有的表
canal.instance.filter.regex =.*\\..*
4、重启canal
当canal监听到binlog发生变化,会通知canal客户端。
三、java使用canal客户端
1、依赖
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.client</artifactId>
<version>1.1.2</version>
</dependency>
2、核心代码
import com.alibaba.fastjson.JSONObject;
import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.client.CanalConnectors;
import com.alibaba.otter.canal.protocol.CanalEntry;
import com.alibaba.otter.canal.protocol.Message;
import com.google.protobuf.ByteString;
import java.net.InetSocketAddress;
import java.util.List;
public class CanalClient {
public static void main(String[] args) throws Exception{
//1.获取 canal 连接对象
CanalConnector canalConnector =
CanalConnectors.newSingleConnector(new
InetSocketAddress("canal所在服务器IP", 11111), "example", "", "");
System.out.println("canal启动并开始监听数据 ...... ");
while (true){
canalConnector.connect();
//订阅表
canalConnector.subscribe("shop001.*");
//获取数据
Message message = canalConnector.get(100);
//解析message
List<CanalEntry.Entry> entries = message.getEntries();
if(entries.size() <=0){
System.out.println("未检测到数据");
Thread.sleep(1000);
}
for(CanalEntry.Entry entry : entries){
//1、获取表名
String tableName = entry.getHeader().getTableName();
//2、获取类型
CanalEntry.EntryType entryType = entry.getEntryType();
//3、获取序列化后的数据
ByteString storeValue = entry.getStoreValue();
//判断是否rowdata类型数据
if(CanalEntry.EntryType.ROWDATA.equals(entryType)){
//对第三步中的数据进行解析
CanalEntry.RowChange rowChange = CanalEntry.RowChange.parseFrom(storeValue);
//获取当前事件的操作类型
CanalEntry.EventType eventType = rowChange.getEventType();
//获取数据集
List<CanalEntry.RowData> rowDatasList = rowChange.getRowDatasList();
//便利数据
for(CanalEntry.RowData rowData : rowDatasList){
//数据变更之前的内容
JSONObject beforeData = new JSONObject();
List<CanalEntry.Column> beforeColumnsList = rowData.getAfterColumnsList();
for(CanalEntry.Column column : beforeColumnsList){
beforeData.put(column.getName(),column.getValue());
}
//数据变更之后的内容
List<CanalEntry.Column> afterColumnsList = rowData.getAfterColumnsList();
JSONObject afterData = new JSONObject();
for(CanalEntry.Column column : afterColumnsList){
afterData.put(column.getName(),column.getValue());
}
System.out.println("Table :" + tableName +
",eventType :" + eventType +
",beforeData :" + beforeData +
",afterData : " + afterData);
}
}else {
System.out.println("当前操作类型为:" + entryType);
}
}
}
}
}
四、springboot使用canal客户端(亲测该方式并不是很友好。。)
1、引入依赖
<dependency>
<groupId>top.javatool</groupId>
<artifactId>canal-spring-boot-starter</artifactId>
<version>1.2.1-RELEASE</version>
</dependency>
2、编写配置
canal:
destination: example # canal的集群名字,要与安装canal时设置的名称一致
server: 192.168.56.10:11111 # canal服务地址
3、监听类
import org.springframework.stereotype.Component;
import top.javatool.canal.client.annotation.CanalTable;
import top.javatool.canal.client.handler.EntryHandler;
@CanalTable("tb_item") //监听的表
@Component
public class ItemHandler implements EntryHandler<Testb> {
@Override
public void insert(Testb item) {
System.out.println("insert");
System.out.println(item);
}
@Override
public void update(Testb before, Testb after) {
System.out.println("update");
System.out.println(before);
System.out.println(after);
}
@Override
public void delete(Testb item) {
System.out.println("delete");
System.out.println(item);
}
}
class Testb{
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Testb{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}