java实现通过canal和mysql同步

实验中需要到的工具

下载 canal.deployer-1.1.6
下载mysql 我用的5.7
java8

mysql的配置

# 打开binlog
log-bin=mysql-bin
# 选择ROW(行)模式
binlog-format=ROW
# 配置MySQL replaction需要定义,不要和canal的slaveId重复
server_id=1

在mysql中测试一下
查看日志开启状态
在这里插入图片描述
查看binlog日志文件列表
在这里插入图片描述
查看当前正在写入的binlong文件
在这里插入图片描述

然后在mysql中创建一个canal账户

-- 创建用户 用户名:canal 密码:Canal@123456
create user 'canal'@'%' identified by 'Canal@123456';
-- 授权 *.*表示所有库
grant SELECT, REPLICATION SLAVE, REPLICATION CLIENT on *.* to 'canal'@'%' identified by 'Canal@123456';


canal配置

先对canal配置
打开cananl.deployer-1.1.6下的conf目录

vim cananl.deployer-1.1.6/conf/canal.properties

主要对下面几项进行配置

canal.ip =127.0.0.1  #canal的地址因为我部署在本机,填写本机地址
canal.port = 11111 #端口
canal.destinations = example #这个后边会用到

然后对cananl.deployer-1.1.6目录下example配置

canal.instance.mysql.slaveId=1234 #这个id和mysql_id要不重复
canal.instance.master.address=127.0.0.1:3306 # mysql的地址
canal.instance.master.journal.name=mysql-bin.000001 #mysql的日志
canal.instance.master.position=154
canal.instance.dbUsername=canal #mysql创建的canal账户
canal.instance.dbPassword=Canal@123456
canal.instance.filter.regex= #这个标识对哪个表进行监视 不写代表所有

以上就是对canal的配置
启动canal
./startup.sh
查看日志
在这里插入图片描述
启动成功

java写代码 查看canal情况

package com.example.demo.util;

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 CanalUtils {
    private static   CanalConnector connector; //连接器
    private final static int BATCH_SIZE = 1000;
    private JSONObject before = new JSONObject();
    private JSONObject after = new JSONObject();
    private String eventType;
    private String tableName;
    public  void connect(String url,int port,String example,String username,String password)throws Exception{
        //TODO 连接canal
        this.connector=CanalConnectors.newSingleConnector(new InetSocketAddress(url,port),example,username,password);
        //TODO 发起连接
        this.connector.connect();
    }
    public void subscribe(String tableName){
        //TODO 订阅监视的表
        if (tableName==null){
            this.connector.subscribe();
        }else {
            this.connector.subscribe(tableName);
        }

    }
    public void getEntry(int clintNum) throws  Exception{
        this.getBefore().clear();
        this.getAfter().clear();

        Message message= this.connector.get(clintNum);
       List<CanalEntry.Entry> entries= message.getEntries();

       if (entries.size()!=0){
           for (CanalEntry.Entry entry : entries) {
               //TODO 获取表名
              tableName = entry.getHeader().getTableName();
                //TODO 获取类型
               CanalEntry.EntryType entryType = entry.getEntryType();
                //TODO 获取数据
               ByteString storeValue = entry.getStoreValue();
               if (CanalEntry.EntryType.ROWDATA.equals(entryType)) {
                   //TODO 序列化数据
                   CanalEntry.RowChange rowChange = CanalEntry.RowChange.parseFrom(storeValue);
                   //TODO 获取数据
                   CanalEntry.EventType  eventType = rowChange.getEventType();
                   this.eventType=eventType.toString();
                   // TODO 获取数据集
                   List<CanalEntry.RowData> rowDataList = rowChange.getRowDatasList();
                    NoSelectRowData(rowDataList);
//                   switch (eventType.toString()){
//                       case "INSERT":
//                           System.out.println("Insert");
//                           NoSelectRowData(rowDataList);
//                           break;
//                       case "DELETE":
//                           System.out.println("DELETE");
//                           NoSelectRowData(rowDataList);
//                           break;
//                       case "SELECT":
//                           System.out.println("SELECT");
//                           NoSelectRowData(rowDataList);
//                           break;
//                       case "UPDATE":
//                           System.out.println("UPDATE");
//                           NoSelectRowData(rowDataList);
//                           break;
//                   }

               }
           }
       }
    }

    /**
     * mysql数据库只执行 修改 删除 添加 操作
     * @param rowDataList
     */
    public void NoSelectRowData(List<CanalEntry.RowData> rowDataList){

        for (CanalEntry.RowData row : rowDataList) {
            List<CanalEntry.Column> beforeColumnsList = row.getBeforeColumnsList();
            beforeColumnsList.forEach(v -> {
                before.put(v.getName(), v.getValue());
            });
            List<CanalEntry.Column> afterColumnsList = row.getAfterColumnsList();
            afterColumnsList.forEach(v -> {
                after.put(v.getName(), v.getValue());
            });
        }
    }
    public String getEventType(){
        return this.eventType;
    }
    public JSONObject getBefore(){
        return this.before;
    }
    public JSONObject getAfter(){
        return  this.after;
    }

}

在man函数中查看

     CanalUtils canalUtils = new CanalUtils();
        canalUtils.connect("localhost",11111,"example","","");
        canalUtils.subscribe(null);
         while (true){
                    canalUtils.getEntry(100);
                    if (canalUtils.getBefore().size()>0||canalUtils.getAfter().size()>0){
                        System.out.println("事件是:"+canalUtils.getEventType());
                        System.out.println("之前数据:" + canalUtils.getBefore());
                        System.out.println("之后数据:" + canalUtils.getAfter());
                    }
         }

执行结果
在这里插入图片描述
然后拿到之前数据和之后数据的情况,写入es或者redis、mq等

### 回答1: Canal是一个开源的数据库增量订阅&消费组件,可以实现MySQL和Redis的同步。它可以通过解析MySQL的binlog日志,将数据变更事件转换成Java对象,然后通过消息队列的方式异步地传递给消费端,消费端可以根据自己的需求进行处理,比如将数据同步到Redis中。Canal支持多种消息队列,包括Kafka、RocketMQ、RabbitMQ等,也可以自定义消息处理器。 ### 回答2: Canal是阿里巴巴开源的一个基于数据库增量日志解析的数据同步工具,通过解析MySQL的binlog日志实现MySQL和Redis的数据同步。 Canal的工作原理如下: 首先,Canal会建立一个轻量级的MySQL实例来监听MySQL的binlog日志,然后解析这些日志文件生成一个逻辑日志,将这些逻辑日志发送给指定的消费端,例如Redis等。 其次,Canal将这些日志文件解析成数据格式,然后将这些格式化的数据推送到指定的消费端。在Redis端,我们可以通过Canal提供的接口来订阅这些数据并将其存储到Redis中。 最后,Canal还支持针对不同表的数据同步,可以通过配置不同的过滤规则来实现不同表的数据同步。 Canal的优点在于: 1. 数据同步实时性高:由于Canal是基于数据增量日志解析的,所以同步数据的实时性非常高,可以达到毫秒级别的数据同步。 2. 可扩展性强:Canal支持横向扩展和纵向扩展,可以随时根据系统负载情况进行扩展。 3. 可配置性强:Canal支持灵活的配置规则,可以根据不同的业务需求进行配置,满足不同的数据同步需求。 总体来说,Canal是一个非常实用的数据同步工具,可以帮助我们解决MySQL和Redis之间的数据同步问题,同时还支持多种数据源的同步,具有很高的可扩展性和可配置性,是一个非常好用的开源工具。 ### 回答3: Canal是阿里巴巴中间件团队开发的一款基于数据库增量日志解析同步工具,支持MySQL、Oracle、SqlServer等多种关系型数据库。Canal通过订阅MySQL的binlog实现MySQL数据的实时同步,同时配合redis实现数据的高速缓存,提高数据访问速度和可靠性。 首先,在Canal的配置文件中,需要设置对MySQL binlog的订阅,包括MySQL的地址、用户名、密码和需要订阅的数据库和表。Canal会根据这些订阅信息,实时监听MySQL数据库的变化,并将变化的数据转化为JSON格式的数据。 其次,配置Canal与redis的连接信息,包括redis的地址和端口号等信息。Canal通过redis的发布和订阅机制,将解析出的JSON格式的数据发布到redis缓存中。 最后,应用程序可根据自己的需求从redis缓存中获取数据,从而实现MySQL和redis同步。相比于直接访问MySQL数据库,Canal和redis的方式可以大大提高数据的访问速度和可靠性,尤其是对于一些关键业务数据的访问,更加有利于保障数据的安全性和完整性。 总之,Canal和redis的组合非常适合需要实时同步MySQL数据并提高访问速度和可靠性的应用场景,具有很好的性能和稳定性,并且易于配置和集成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值