springboot集成阿里canal监控数据库变化

2 篇文章 0 订阅

这个东西啊,刚开始看着很难,但是一步一步操作下来,最后会发现很简单;
那些理论我就不写了,相信大家也都看过了,如果没有看过就搜索一下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

的时候,就是成功了,然后去数据库插入个数据试一下吧

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋秋秋秋秋雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值