canal-server和springboot应用

604 阅读2分钟

介绍单机版的canal-server搭建,实际项目中需要配合canal-admin搭建集群,将采集到的数据发送到kafka,springboot客户端从kafka消费,这里介绍的canal-spring-boot-starter支持从kafka消费

数据库账号创建

先在被监听的数据库里创建一个给canal用的账号

create user canal identified by 'canal';
grant select, show view, replication slave, replication client on *.* to 'canal'@'%';
flush privileges;

docker-compose.yml

version: '3.1'
services:
  canal-server:
    restart: always
    container_name: canal-server
    image: canal/canal-server:latest
    ports:
      - 11111:11111
    volumes:
      - ./server-logs:/home/admin/canal-server/logs
      # 定义一个叫test的实例
      - ./instance/test:/home/admin/canal-server/conf/test

在./instance/test/目录下创建instance.properties文件,内容如下:

canal.instance.master.address=192.168.3.3:3306
canal.instance.dbUsername=canal
canal.instance.dbPassword=canal
canal.instance.connectionCharset=UTF-8
canal.instance.filter.regex=要监听的库名\\..*
canal.instance.parser.parallelThreadSize=1 # CPU核心数
  • canal.instance.master.address要监听的mysql数据库地址
  • canal.instance.dbUsername=canal该mysql数据库给canal使用的用户名
  • canal.instance.dbPassword=canal该mysql数据库给canal使用的密码
  • canal.instance.filter.regex设置要监听的数据库,如test\\..*表示监听test库所有表的变化
  • canal.instance.parser.parallelThreadSize设置该实例canal占用的CPU核心数,测试使用设为1即可

配置还有很多,比如设置binlog的position等,可从canal官方文档中查阅

springboot配置

canal:
  mode: simple
  filter: # 过滤表名,可以为空
  batch-size: 1
  timeout: 1
  server: 192.168.3.3:11111
  destination: # canal-server中定义的实例名,不可以为空
  user-name: canal
  password: canal
  async: true # 必须是true,设为false在启动时会报MessageHandler bean找不到,具体原因没看

springboot消费

pom.xml中引入canal-spring-boot-starter

<dependency>
  <groupId>top.javatool</groupId>
  <artifactId>canal-spring-boot-starter</artifactId>
  <version>1.2.1-RELEASE</version>
</dependency>

这个包之前在《canal-spring-boot-starter修改》文章中讲过需要自己拉源码修改后才好用

假设有数据库里面有test表,对应的实体类是Test,按照下面这样定义一个消费者,就可以对Test这个表的改动进行监听

@Slf4j
@Component
@CanalTable(value = "表名")
public class TestConsumer implements EntryHandler<Test> {
    @Override
    public void insert(Test test) {
        log.info("新增,{}", test);
    }

    /**
     * @param before 只包含变更的属性
     * @param after 包含所有属性
     */
    @Override
    public void update(Test before, Test after) {
        log.info("更新,更新前={},更新后={}", before, after);
    }

    @Override
    public void delete(Test test) {
        log.info("删除,{}", test);
    }
}

建议采用策略模式去处理不同表不同字段的处理逻辑

统一处理

统一对所有监听的表进行处理,是将表字段和值放到Map里,字段名为Map的key,字段值为Map的value

@Slf4j
@Component
@CanalTable(value = "all")
public class AllConsumer implements EntryHandler<Map<String, String>> {
    @Override
    public void insert(Map<String, String> map) {
        log.info("新增,{}", map);
    }

    @Override
    public void update(Map<String, String> before, Map<String, String> after) {
        // CanalModel可以得到当前这次的库名和表名
        CanalModel canal = CanalContext.getModel();
        log.info("更新,更新前={},更新后={}", before, after);
    }

    @Override
    public void delete(Map<String, String> map) {
        log.info("删除,{}", map);
    }
}

公众号:飞翔的代码