Canal实现0侵入同步缓存数据

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 Tair(兼容Redis),内存型 2GB
简介: Canal实现0侵入同步缓存数据

开启MySQL binlog功能

cd /home/mysql8/conf

vim my.cnf

[mysqld]
log-bin=/var/lib/mysql/mysql-bin # 开启 binlog,这里路径来自Docker安装mysql的时,挂载目录是/var/lib/mysql
binlog-format=ROW # 选择 ROW 模式
server_id=1 # 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复
binlog-do-db=imooc-hire-dev # 配置binlog给哪个数据库使用,可以配多个

重启MySQL:

docker restart mysql

检测binlog是否开启:

Docker安装Canal

docker pull canal/canal-server:v1.1.6
docker run -p 11111:11111 --name canal -e canal.destinations=imooc -e canal.instance.mysql.slaveId=20231111 -e canal.instance.master.address=192.168.233.128:3306 -e canal.instance.dbUsername=root -e canal.instance.dbPassword=Admin~123456 -e canal.instance.connectionCharset=UTF-8 -e canal.instance.filter.regex=imooc-hire-dev.data_dictionary --restart=always -d canal/canal-server:v1.1.6

canal.destinations=imooc表示起个名字跟后面的yml中对应上即可;

canal.instance.master.address=192.168.233.128:3306表示监听的数据库ip和端口;

canal.instance.filter.regex=imooc-hire-dev.data_dictionary表示的是监听imooc-hire-dev库的data_dictionary表,可以逗号分隔,监听多张表;

canal.instance.dbUsername=root -e canal.instance.dbPassword=Admin~123456表示被监听的数据库账号密码;

查看是否启动成功:

docker exec -it canal bash
cd canal-server/logs/imooc
vi imooc.log

不报错就对了。

SpringBoot集成Canal实现0侵入缓存同步

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

yml

canal:
  destination: imooc
  server: 192.168.233.128:11111
  user-name: canal
  password: canal
logging:
  level:
    top.javatool.canal.client: warn
package com.imooc.canal;
import com.imooc.base.BaseInfoProperties;
import com.imooc.pojo.DataDictionary;
import com.imooc.pojo.co.DataDictionaryCO;
import com.imooc.utils.GsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import top.javatool.canal.client.annotation.CanalTable;
import top.javatool.canal.client.handler.EntryHandler;
import java.util.ArrayList;
import java.util.List;
@CanalTable("data_dictionary")      // 指定监听的表名
@Component
public class DataDictSyncHelper extends BaseInfoProperties
        implements EntryHandler<DataDictionaryCO> // 指定表关联的实体对象(javabean)
{
    private static final String DDKEY_PREFIX = DATA_DICTIONARY_LIST_TYPECODE + ":";
    @Override
    public void insert(DataDictionaryCO dataDictionary) {
        String ddkey = DDKEY_PREFIX + dataDictionary.getType_code();
        // 先查询redis中是否存在该数据字典list
        String ddListStr = redis.get(ddkey);
        List<DataDictionary> redisDDList = null;
        if (StringUtils.isBlank(ddListStr)) {
            // 如果不存在,则直接new一个list,添加并存入到redis中即可
            redisDDList = new ArrayList<>();
        } else {
            // 如果redis中存在该list,则直接在缓存的list中新增即可
            redisDDList = GsonUtils.stringToListAnother(ddListStr,
                                                        DataDictionary.class);
        }
        // 转换对象并且塞入list
        DataDictionary pendingDictionary = convertDD(dataDictionary);
        redisDDList.add(pendingDictionary);
        redis.set(ddkey, GsonUtils.object2String(redisDDList));
    }
    private DataDictionary convertDD(DataDictionaryCO dataDictionaryCO) {
        DataDictionary pendingDictionary = new DataDictionary();
        BeanUtils.copyProperties(dataDictionaryCO, pendingDictionary);
        pendingDictionary.setTypeCode(dataDictionaryCO.getType_code());
        pendingDictionary.setTypeName(dataDictionaryCO.getType_name());
        pendingDictionary.setItemKey(dataDictionaryCO.getItem_key());
        pendingDictionary.setItemValue(dataDictionaryCO.getItem_value());
        return pendingDictionary;
    }
    @Override
    public void update(DataDictionaryCO before, DataDictionaryCO after) {
        String ddkey = DDKEY_PREFIX + after.getType_code();
        // 先查询redis中是否存在该数据字典list
        String ddListStr = redis.get(ddkey);
        List<DataDictionary> redisDDList = null;
        if (StringUtils.isBlank(ddListStr)) {
            // 如果不存在,啥都不要干
        } else {
            // 如果redis中存在该list,则直接在缓存的list中修改对应的数据字典项就行,再重置缓存
            redisDDList = GsonUtils.stringToListAnother(ddListStr,
                                                        DataDictionary.class);
            for (DataDictionary dd : redisDDList) {
                if (dd.getId().equalsIgnoreCase(after.getId())) {
                    DataDictionary pendingDictionary = convertDD(after);
                    redisDDList.remove(dd);
                    redisDDList.add(pendingDictionary);
                    break;
                }
            }
            redis.set(ddkey, GsonUtils.object2String(redisDDList));
        }
    }
    @Override
    public void delete(DataDictionaryCO dataDictionary) {
        String ddkey = DDKEY_PREFIX + dataDictionary.getType_code();
        // 先查询redis中是否存在该数据字典list
        String ddListStr = redis.get(ddkey);
        List<DataDictionary> redisDDList = null;
        if (StringUtils.isBlank(ddListStr)) {
            // 如果不存在,啥都不要干
        } else {
            // 如果redis中存在该list,则直接在缓存的list中删除该数据字典项就行,再重置缓存
            redisDDList = GsonUtils.stringToListAnother(ddListStr,
                                                        DataDictionary.class);
            for (DataDictionary dd : redisDDList) {
                if (dd.getId().equalsIgnoreCase(dataDictionary.getId())) {
                    redisDDList.remove(dd);
                    break;
                }
            }
            redis.set(ddkey, GsonUtils.object2String(redisDDList));
        }
    }
}


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
2月前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(一)
数据的存储--Redis缓存存储(一)
112 1
|
2月前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(二)
数据的存储--Redis缓存存储(二)
53 2
数据的存储--Redis缓存存储(二)
|
3月前
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
5月前
|
缓存 NoSQL Java
Redis 缓存与数据库数据不一致问题
Redis 缓存与数据库数据不一致问题
115 3
|
1月前
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
44 5
|
5月前
|
存储 缓存 中间件
|
1月前
|
存储 缓存 算法
分布式缓存有哪些常用的数据分片算法?
【10月更文挑战第25天】在实际应用中,需要根据具体的业务需求、数据特征以及系统的可扩展性要求等因素综合考虑,选择合适的数据分片算法,以实现分布式缓存的高效运行和数据的合理分布。
|
2月前
|
缓存 监控 前端开发
处理页面缓存中数据不一致的问题
【10月更文挑战第9天】
61 2
|
2月前
|
消息中间件 缓存 NoSQL
大数据-49 Redis 缓存问题中 穿透、雪崩、击穿、数据不一致、HotKey、BigKey
大数据-49 Redis 缓存问题中 穿透、雪崩、击穿、数据不一致、HotKey、BigKey
67 2
|
4月前
|
缓存 NoSQL Linux
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
146 1
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据