SpringBoot整合canal实现缓存更新

canal是阿里巴巴的开源组件,用于监听MySQL的binlog日志而实现消息的同步机制,提供增量数据订阅和消费。

canal必须基于MySQL的主从架构才可使用,canal会伪装成MySQL的一个slave节点,然后向MySQL的master发起dump命令,master会将数据库的增量操作写入binlog,然后将binlog通过网络IO发送给canal-server,canal-server解析后将相关信息发送给订阅了该canal-server的客户端。

本次项目中整合canal用于实现缓存的异步更新。

首先拉去canal的镜像(我采用用最新的1.1.5):

docker pull canal/canal-server:v1.1.5

查看docker镜像是否拉取成功:

[root@iZ2vc97qcawcm6uqblda2fZ ~]# docker images
REPOSITORY           TAG       IMAGE ID       CREATED         SIZE
mysql                8.0       33037edcac9b   47 hours ago    444MB
hello-world          latest    feb5d9fea6a5   9 months ago    13.3kB
canal/canal-server   v1.1.5    0c7f1d62a7d8   15 months ago   874MB
[root@iZ2vc97qcawcm6uqblda2fZ ~]# 

启动canal镜像(启动时添加相关的参数):

docker run -p 11111:11111 --name canal \
-e canal.auto.scan=false \
-e canal.destinations=recl \
-e canal.instance.master.address=47.108.105.42:3306 \
-e canal.instance.dbUsername=canal \
-e canal.instance.dbPassword=canal \
-e canal.instance.connectionCharset=UTF-8 \
-e canal.instance.tsdb.enable=true \
-e canal.instance.gtidon=false \
-e canal.instance.filter.regex=recl\\..* \
--network recl \
-d canal/canal-server:v1.1.5

这里解释一下重要参数:

canal.destinations代表客户端需要订阅的主题,只有订阅该主题,才可以接受canal的消息

canal.instance.master.address代表MySQL的master的地址

canal.instance.dbUserName代表MySQL中的对应用户名(在MySQL主库中需要创建一个canal用户并分配相关权限)

canal.instance.dbPassword代表canal用户的密码

canal.instance.filer.regex代表通过正则表达式过滤不需要监听的数据库

查看canal-server是否成功启动(已成功启动):

[root@iZ2vc97qcawcm6uqblda2fZ ~]# docker ps
CONTAINER ID   IMAGE                       COMMAND                  CREATED        STATUS       PORTS                                                                           NAMES
893d281152af   canal/canal-server:v1.1.5   "/alidata/bin/main.s…"   3 hours ago    Up 3 hours   9100/tcp, 11110/tcp, 11112/tcp, 0.0.0.0:11111->11111/tcp, :::11111->11111/tcp   canal
05ec74877d7d   mysql:8.0                   "docker-entrypoint.s…"   16 hours ago   Up 4 hours   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp                            mysql01
[root@iZ2vc97qcawcm6uqblda2fZ ~]# 

接下来开始配置MySQL:

首先更改MySQL的my.cnf文件:

打开my.conf添加配置信息:

log-bin=mysql-bin
# 需要生成binlog日志的数据库名称(我的是recl)
binlog-do-db=recl
# binlog的语句类型
binlog-format=ROW
# 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复
server_id=1

重启MySQL使配置生效,然后检查是否生效(通过show master status;指令查看,下图显示已生效):

创建canal用户并授权:

CREATE USER canal IDENTIFIED BY 'canal';
GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;  
FLUSH PRIVILEGES;
show grants for 'canal'@'%%';

接下来是springboot整合canal:

首先引入canal的starter依赖:

<!--  canal  -->
<dependency>

      <groupId>top.javatool</groupId>

      <artifactId>canal-spring-boot-starter</artifactId>

      <version>1.2.1-RELEASE</version>

</dependency>

application.properties里添加配置(destination为主题):
 

# Canal配置
canal.destination=recl
canal.server=47.108.105.42:11111

创建实体类实现canal的消息监听:

package com.ren.fm.canal;

import com.alibaba.fastjson.JSON;
import com.ren.fm.entity.ReclFm;
import org.springframework.stereotype.Component;
import top.javatool.canal.client.annotation.CanalTable;
import top.javatool.canal.client.handler.EntryHandler;


/**
 * @ClassName: CanalHandler
 * @Description: TODO
 * @Author: RZY
 * @DATE: 2022/7/14 23:14
 * @Version: v1.0
 */

@Component
@CanalTable("recl_fm")
public class ReclFmCanalHandler implements EntryHandler<ReclFm> {

    @Override
    public void insert(ReclFm reclFm) {
        System.out.println("insert:" + reclFm);
        //以下为缓存的更新操作
    }

    @Override
    public void update(ReclFm before, ReclFm after) {
        System.out.println("before:" + JSON.toJSONString(before));
        System.out.println("after:" + JSON.toJSONString(after));
        //以下为缓存的更新操作
    }

    @Override
    public void delete(ReclFm reclFm) {
        System.out.println("delete:" + reclFm);
        //以下为缓存的更新操作
    }
}

ReclFm为实体类(@Column声音字段别名,因为可以存在驼峰转换问题;此为如果存在数据库以下字段可以加上@Transient):

package com.ren.fm.entity;

import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.*;

import java.util.Date;

import java.io.Serializable;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.data.annotation.Id;

import javax.persistence.Column;

/**
 * <p>
 * 
 * </p>
 *
 * @author RZY
 * @since 2022-07-13
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="ReclFm对象", description="")
@TableName("recl_fm")
public class ReclFm implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "fm唯一id")
    @TableId(value = "id", type = IdType.ID_WORKER)
    @Id
    private Long id;

    @ApiModelProperty(value = "上传用户id")
    @Column(name = "upload_user_id")
    private Long uploadUserId;

    @ApiModelProperty(value = "fm音频对应oss地址")
    @Column(name = "fm_url")
    private String fmUrl;

    @ApiModelProperty(value = "fm所属心情")
    @Column(name = "fm_mood")
    private String fmMood;

    @ApiModelProperty(value = "fm作者签名")
    @Column(name = "fm_sign")
    private String fmSign;

    @ApiModelProperty(value = "fm标题")
    @Column(name = "fm_title")
    private String fmTitle;

    @ApiModelProperty(value = "fm封面图片对应oss地址")
    @Column(name = "fm_cover")
    private String fmCover;

    @ApiModelProperty(value = "fm收藏量")
    @Column(name = "fm_collection_count")
    private Long fmCollectionCount;

    @ApiModelProperty(value = "fm浏览量")
    @Column(name = "fm_view_count")
    private Long fmViewCount;

    @ApiModelProperty(value = "fm评论量")
    @Column(name = "fm_comment_count")
    private Long fmCommentCount;

    @ApiModelProperty(value = "fm点赞量")
    @Column(name = "fm_praise_count")
    private Long fmPraiseCount;

    @ApiModelProperty(value = "当前状态(‘Draft’代表审核中, ’remove‘代表下架, ‘Modify’代表内容不符需修改, ‘Verify’代表已上架)")
    @Column(name = "status")
    private String status;

    @ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
    @Column(name = "isDeleted")
    @TableLogic
    private Boolean isDeleted;

    @ApiModelProperty(value = "创建时间")
    @Column(name = "gmt_create")
    @TableField(fill = FieldFill.INSERT)
    private Date gmtCreate;

    @ApiModelProperty(value = "更新时间")
    @Column(name = "gmt_modified")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date gmtModified;


}

最后进行测试阶段:

2022-07-15 13:54:21.533  INFO 9580 --- [l-client-thread] t.j.c.client.client.AbstractCanalClient  : 获取消息 Message[id=31,entries=[header {
  version: 1
  logfileName: "mysql-bin.000003"
  logfileOffset: 18599
  serverId: 1
  serverenCode: "UTF-8"
  executeTime: 1657864460000
  sourceType: MYSQL
  schemaName: ""
  tableName: ""
  eventLength: 84
}
entryType: TRANSACTIONBEGIN
storeValue: " \341\003"
, header {
  version: 1
  logfileName: "mysql-bin.000003"
  logfileOffset: 18768
  serverId: 1
  serverenCode: "UTF-8"
  executeTime: 1657864460000
  sourceType: MYSQL
  schemaName: "recl"
  tableName: "recl_fm"
  eventLength: 772
  eventType: UPDATE
  props {
    key: "rowsCount"
    value: "1"
  }
}
entryType: ROWDATA
storeValue: "\bV\020\002P\000b\312\017\n4\b\000\020\373\377\377\377\377\377\377\377\377\001\032\002id \001(\0000\000B\0231444208758042406913R\006bigint\n@\b\001\020\373\377\377\377\377\377\377\377\377\001\032\016upload_user_id \000(\0000\000B\0231502211201646481410R\006bigint\n\240\001\b\002\020\f\032\006fm_url \000(\0000\000B~https://recl-edu.oss-cn-beijing.aliyuncs.com/recl-music/d99df82714894f08bb9a18c258731b35Alec Benjamin - Let Me Down Slowly.mp3R\fvarchar(255)\n*\b\003\020\f\032\afm_mood \000(\0000\000B\b\346\202\262\344\274\24411R\vvarchar(20)\nU\b\004\020\f\032\afm_sign \000(\0000\000B3\345\206\263\345\256\232\344\270\244\344\270\252\344\272\272\350\203\275\345\220\246\345\234\250\344\270\200\350\265\267\347\232\204\345\233\240\347\264\240\346\234\211\345\276\210\345\244\232\343\200\202R\vvarchar(50)\n.\b\005\020\f\032\bfm_title \000(\0000\000B\vlet me downR\vvarchar(20)\n\204\001\b\006\020\f\032\bfm_cover \000(\0000\000B`https://recl-edu.oss-cn-beijing.aliyuncs.com/2021/10/02/316de4ea0907483aa6de4ea0446b4c5afile.pngR\fvarchar(255)\n3\b\a\020\373\377\377\377\377\377\377\377\377\001\032\023fm_collection_count \000(\0000\000B\0010R\006bigint\n-\b\b\020\373\377\377\377\377\377\377\377\377\001\032\rfm_view_count \000(\0000\000B\0010R\006bigint\n0\b\t\020\373\377\377\377\377\377\377\377\377\001\032\020fm_comment_count \000(\0000\000B\0010R\006bigint\n/\b\n\020\373\377\377\377\377\377\377\377\377\001\032\017fm_praise_count \000(\0000\000B\0010R\006bigint\n\'\b\v\020\f\032\006status \000(\0000\000B\006VerifyR\vvarchar(10)\n.\b\f\020\372\377\377\377\377\377\377\377\377\001\032\nis_deleted \000(\0000\000B\0010R\ntinyint(1)\n5\b\r\020]\032\ngmt_create \000(\0000\000B\0232022-07-13 12:46:24R\bdatetime\n7\b\016\020]\032\fgmt_modified \000(\0000\000B\0232022-07-13 12:46:26R\bdatetime\0224\b\000\020\373\377\377\377\377\377\377\377\377\001\032\002id \001(\0000\000B\0231444208758042406913R\006bigint\022@\b\001\020\373\377\377\377\377\377\377\377\377\001\032\016upload_user_id \000(\0000\000B\0231502211201646481410R\006bigint\022\240\001\b\002\020\f\032\006fm_url \000(\0000\000B~https://recl-edu.oss-cn-beijing.aliyuncs.com/recl-music/d99df82714894f08bb9a18c258731b35Alec Benjamin - Let Me Down Slowly.mp3R\fvarchar(255)\022*\b\003\020\f\032\afm_mood \000(\0010\000B\b\346\202\262\344\274\24499R\vvarchar(20)\022U\b\004\020\f\032\afm_sign \000(\0000\000B3\345\206\263\345\256\232\344\270\244\344\270\252\344\272\272\350\203\275\345\220\246\345\234\250\344\270\200\350\265\267\347\232\204\345\233\240\347\264\240\346\234\211\345\276\210\345\244\232\343\200\202R\vvarchar(50)\022.\b\005\020\f\032\bfm_title \000(\0000\000B\vlet me downR\vvarchar(20)\022\204\001\b\006\020\f\032\bfm_cover \000(\0000\000B`https://recl-edu.oss-cn-beijing.aliyuncs.com/2021/10/02/316de4ea0907483aa6de4ea0446b4c5afile.pngR\fvarchar(255)\0223\b\a\020\373\377\377\377\377\377\377\377\377\001\032\023fm_collection_count \000(\0000\000B\0010R\006bigint\022-\b\b\020\373\377\377\377\377\377\377\377\377\001\032\rfm_view_count \000(\0000\000B\0010R\006bigint\0220\b\t\020\373\377\377\377\377\377\377\377\377\001\032\020fm_comment_count \000(\0000\000B\0010R\006bigint\022/\b\n\020\373\377\377\377\377\377\377\377\377\001\032\017fm_praise_count \000(\0000\000B\0010R\006bigint\022\'\b\v\020\f\032\006status \000(\0000\000B\006VerifyR\vvarchar(10)\022.\b\f\020\372\377\377\377\377\377\377\377\377\001\032\nis_deleted \000(\0000\000B\0010R\ntinyint(1)\0225\b\r\020]\032\ngmt_create \000(\0000\000B\0232022-07-13 12:46:24R\bdatetime\0227\b\016\020]\032\fgmt_modified \000(\0000\000B\0232022-07-13 12:46:26R\bdatetime"
],raw=true,rawEntries=[]]
before:{"fmMood":"悲伤11"}
after:{"fmCollectionCount":0,"fmCommentCount":0,"fmCover":"https://recl-edu.oss-cn-beijing.aliyuncs.com/2021/10/02/316de4ea0907483aa6de4ea0446b4c5afile.png","fmMood":"悲伤99","fmPraiseCount":0,"fmSign":"决定两个人能否在一起的因素有很多。","fmTitle":"let me down","fmUrl":"https://recl-edu.oss-cn-beijing.aliyuncs.com/recl

成功的拿到了消息,说明配置成功了

补充:由于MySQL版本差异,5.6及以上版本的密码验证改变为mysql_native_password,因此canal可以会出现密码验证问题,在MySQL中执行以下命令即可:

ALTER USER 'canal'@'%' IDENTIFIED WITH mysql_native_password BY 'canal';

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值