开启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)); } } }