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

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生内存数据库 Tair,内存型 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 算法
17- 数据库有1000万数据 ,Redis只能缓存20w数据, 如何保证Redis中的数据都是热点数据 ?
保证Redis中的20w数据为热点数据,可以通过设置Redis的LFU(Least Frequently Used)淘汰策略。这样,当数据库有1000万数据而Redis仅能缓存20w时,LFU会自动移除使用频率最低的项,确保缓存中的数据是最常使用的。
86 8
|
27天前
|
存储 缓存 测试技术
有效使用缓存时需要缓存动态数据吗?
【6月更文挑战第7天】本文探讨了如何有效地缓存数据以提升应用性能。关键在于选择合适的数据进行缓存和适时缓存。缓存不应被视为永久存储,应同时维护原始数据存储。
76 2
有效使用缓存时需要缓存动态数据吗?
|
29天前
|
缓存 NoSQL 中间件
应对数据库不断膨胀的数据:缓存和队列中间件
【6月更文挑战第5天】该文探讨了优化数据库使用以提升应用系统性能的策略。文中建议利用Redis缓存和MQ消息队列作为辅助工具,以进一步优化性能和减少资源消耗。
27 2
应对数据库不断膨胀的数据:缓存和队列中间件
|
13天前
|
缓存 安全 算法
Go 中使用 map 实现高效的数据缓存
Go 中使用 map 实现高效的数据缓存
|
2天前
|
存储 缓存 NoSQL
实现返利App中的数据缓存与预加载机制
实现返利App中的数据缓存与预加载机制
|
2天前
|
存储 缓存 Prometheus
Java中数据缓存的优化与实现策略
Java中数据缓存的优化与实现策略
|
2天前
|
数据采集 缓存 API
淘宝商品详情数据(实时更新,缓存数据)
淘宝商品详情数据,关键用于电商业务和市场分析,包括属性、价格、库存等信息。可通过淘宝开放平台API注册获取权限,调用如`taobao.item.get`接口,或使用爬虫技术。数据可实时更新,也有缓存选项。注意API权限、数据安全和调用限制。第三方服务也是获取数据的途径,但可能非实时且成本高。有效利用数据支持决策和分析。
14 0
|
3天前
|
存储 缓存 安全
解析Java中的数据缓存技术
解析Java中的数据缓存技术
|
2月前
|
消息中间件 缓存 监控
中间件如果缓存中存在所需的数据(缓存命中)
【5月更文挑战第12天】中间件如果缓存中存在所需的数据(缓存命中)
37 3
|
2月前
|
存储 缓存 监控