这个东西啊,刚开始看着很难,但是一步一步操作下来,最后会发现很简单;
那些理论我就不写了,相信大家也都看过了,如果没有看过就搜索一下canal原理,有很多讲解了,这篇文章旨在让大家能够按不走就直接能配置成功;
我这里是在windos10的环境下配置的,linux配置只是操作不同而已,但是步骤是一样的;
一、数据库的配置
1. 开启binlog功能
只要修改mysql的my.ini文件,在[mysqld]下面添加如下代码
log-bin=mysql-bin
binlog-format=ROW
server_id=1
至于每行代表啥,不用关心他;
重启数据库
命令行运行一下
show variables like ‘%log_bin%’
看看开启没有,不运行也没事,基本上重启后都会开启
2. 为canal创建账号
这一步应该也是必须的,因为刚开始我用root账号,但是不管用
把下面的话复制到命令行就可以了
CREATE USER canal IDENTIFIED BY 'canal';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;
FLUSH PRIVILEGES;
到这里数据库就完事了,不用管乱七八糟的东西,就按不走一步一步来,绝对没问题;
二、canal服务端
1. 下载canal
官方的下载太慢太慢了,我把我百度网盘的分享出来(看我多良心,其他的提供下载的都是要积分才能下载)
链接:https://pan.baidu.com/s/1rRa1w-aPwm-DTtiAaqfwGQ 提取码:2xdj
将下载的文件解压,解压后找到conf\example\instance.properties配置文件
2. 修改配置文件内容
#自己的数据库
canal.instance.master.address=127.0.0.1:3306
#刚才创建的用户名和密码
canal.instance.dbUsername=canal
canal.instance.dbPassword=canal
#监听所有表 可以改成想要监听的表,用,分隔
canal.instance.filter.regex=.*\\..*
这里怕大家乱,所以把我的配置文件直接贴上来,我已经把没用的行都删了,直接复制过去就可以,然后改那三个注释的地方就可以了
canal.instance.gtidon=false
# 自己的数据库
canal.instance.master.address=127.0.0.1:3306
canal.instance.master.journal.name=
canal.instance.master.position=
canal.instance.master.timestamp=
canal.instance.master.gtid=
canal.instance.rds.accesskey=
canal.instance.rds.secretkey=
canal.instance.rds.instanceId=
canal.instance.tsdb.enable=true
# 刚才创建的数据库用户和密码
canal.instance.dbUsername=canal
canal.instance.dbPassword=canal
canal.instance.connectionCharset = UTF-8
canal.instance.enableDruid=false
# 监控的表,这个代表全部,
canal.instance.filter.regex=.*\\..*
canal.instance.filter.black.regex=mysql\\.slave_.*
canal.mq.topic=example
canal.mq.partition=0
3. 找到canal.deployer-1.1.5\bin\startup.bat启动
启动后看到Listening for transport dt_socket at address: 9099就是成功了
三、canal客户端
1.首先你要创建一个springboot的项目
至于怎么创建…百度 >>创建springboot项目<<很多很多
2.pom引入
<!--阿里 canal数据库监听工具-->
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.client</artifactId>
<version>1.1.4</version>
</dependency>
3.创建CannalClient类
直接复制过去就行了,里面的代码代表啥???复制过去之后再看,在这里看的确比较乱
package com.canal;
import com.alibaba.otter.canal.client.CanalConnectors;
import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.common.utils.AddressUtils;
import com.alibaba.otter.canal.protocol.Message;
import com.alibaba.otter.canal.protocol.CanalEntry.Column;
import com.alibaba.otter.canal.protocol.CanalEntry.Entry;
import com.alibaba.otter.canal.protocol.CanalEntry.EntryType;
import com.alibaba.otter.canal.protocol.CanalEntry.EventType;
import com.alibaba.otter.canal.protocol.CanalEntry.RowChange;
import com.alibaba.otter.canal.protocol.CanalEntry.RowData;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import java.net.InetSocketAddress;
import java.util.List;
/**
* @date 2020-08-06 23:00
**/
@Component
public class CannalClient implements InitializingBean {
private final static int BATCH_SIZE = 1000;
@Override
public void afterPropertiesSet() throws Exception {
// 创建链接
CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress(AddressUtils.getHostIp(), 11111), "example", "", "");
int batchSize = 1000;
int emptyCount = 0;
try {
//建立连接
connector.connect();
//设置监听的表 如果这里配置了,那么配置文件里配置的就失效了
//sys-demo是数据库,meituan_info是表,如果是全部,那就不用配置了,因为配置文件已经配置了
connector.subscribe("sys-demo.meituan_info");
connector.rollback();
//设置监控次数,如果监控超过次数后就自动关闭,如果想一直监控 while就设置为true
int totalEmptyCount = 99999;
while (emptyCount < totalEmptyCount) {
// 获取指定数量的数据
Message message = connector.getWithoutAck(batchSize);
long batchId = message.getId();
int size = message.getEntries().size();
if (batchId == -1 || size == 0) {
emptyCount++;
System.out.println("empty count : " + emptyCount);
try {
//休眠一秒
Thread.sleep(1000);
} catch (InterruptedException ignored) {}
} else {
emptyCount = 0;
//数据有更新
printEntry(message.getEntries());
}
// 提交确认
connector.ack(batchId);
}
System.out.println("empty too many times, exit");
} finally {
connector.disconnect();
}
}
/**
* 打印canal server解析binlog获得的实体类信息
*/
private static void printEntry(List<Entry> entrys) {
for (Entry entry : entrys) {
if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND) {
continue;
}
RowChange rowChage;
try {
rowChage = RowChange.parseFrom(entry.getStoreValue());
} catch (Exception e) {
throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + entry.toString(), e);
}
//获取操作类型
EventType eventType = rowChage.getEventType();
System.out.println(String.format("================binlog[%s:%s] , name[%s,%s] , eventType : %s",
entry.getHeader().getLogfileName(), entry.getHeader().getLogfileOffset(),
entry.getHeader().getSchemaName(), entry.getHeader().getTableName(),
eventType));
for (RowData rowData : rowChage.getRowDatasList()) {
if (eventType == EventType.DELETE) {
//删除
printColumn(rowData.getBeforeColumnsList());
} else if (eventType == EventType.INSERT) {
//插入
printColumn(rowData.getAfterColumnsList());
} else {
//更新
System.out.println("-------before");
printColumn(rowData.getBeforeColumnsList());
System.out.println("-------after");
printColumn(rowData.getAfterColumnsList());
}
}
}
}
private static void printColumn(List<Column> columns) {
for (Column column : columns) {
System.out.println(">>>"+column.getName() + "=" + column.getValue());
}
}
}
然后…然后就没了,启动项目就行了,当看到
empty count : 1
empty count : 2
…
的时候,就是成功了,然后去数据库插入个数据试一下吧