canal icon indicating copy to clipboard operation
canal copied to clipboard

DML日志正常,但是数据未同步至MYSQL数据库

Open ImCz208 opened this issue 2 years ago • 3 comments

Question

adapter日志中每一条变更日志都有,但是变更没有同步至目标数据库

ImCz208 avatar Jun 15 '23 09:06 ImCz208

我也遇到同样的问题,版本用的是1.1.6,你解决了吗

it-xiaomi avatar Jun 16 '23 09:06 it-xiaomi

client-adapter/rdb/src/main/java/com/alibaba/otter/canal/client/adapter/rdb/service/RdbMirrorDbSyncService.java

/**
     * 初始化表配置
     *
     * @param key 配置key: destination.database.table
     * @param baseConfigMap db sync config
     * @param dml DML
     */
    private void initMappingConfig(String key, MappingConfig baseConfigMap, MirrorDbConfig mirrorDbConfig, Dml dml) {
        MappingConfig mappingConfig = mirrorDbConfig.getTableConfig().get(key);
        if (mappingConfig == null) {
            // 构造表配置
            mappingConfig = new MappingConfig();
            mappingConfig.setDataSourceKey(baseConfigMap.getDataSourceKey());
            mappingConfig.setDestination(baseConfigMap.getDestination());
            mappingConfig.setGroupId(baseConfigMap.getGroupId());
            mappingConfig.setOuterAdapterKey(baseConfigMap.getOuterAdapterKey());
            mappingConfig.setConcurrent(baseConfigMap.getConcurrent());
            MappingConfig.DbMapping dbMapping = new MappingConfig.DbMapping();
            mappingConfig.setDbMapping(dbMapping);
            dbMapping.setDatabase(dml.getDatabase());
            dbMapping.setTable(dml.getTable());
            dbMapping.setTargetDb(dml.getDatabase());// 目标数据库
            dbMapping.setTargetTable(dml.getTable());// 目标表,从dml解析,就是binlog解析出来的库和表名
            dbMapping.setMapAll(true);
            List<String> pkNames = dml.getPkNames();
            Map<String, String> pkMapping = new LinkedHashMap<>();
            pkNames.forEach(pkName -> pkMapping.put(pkName, pkName));
            dbMapping.setTargetPk(pkMapping);

            mirrorDbConfig.getTableConfig().put(key, mappingConfig);
        }
    }

mirrorDbConfigCache中的mappingConfig是rdb相关配置文件的内容,tableConfig的数据在initMappingConfig方法中赋值,数据与mappingConfig差不多,但数据库名和表名是从dml解析出来的

/**
     * 批量同步Dml
     *
     * @param dmlList Dml列表,不包含DDL
     */
    private void syncDml(List<Dml> dmlList) {
        if (dmlList == null || dmlList.isEmpty()) {
            return;
        }
        rdbSyncService.sync(dmlList, dml -> {
            MirrorDbConfig mirrorDbConfig = mirrorDbConfigCache.get(dml.getDestination() + "." + dml.getDatabase());
            if (mirrorDbConfig == null) {
                return false;
            }
            // 原代码
//            String table = dml.getTable();
//            MappingConfig config = mirrorDbConfig.getTableConfig().get(table);
            MappingConfig config = mirrorDbConfig.getMappingConfig();// 修改代码

            if (config == null) {
                return false;
            }
            rdbSyncService.appendDmlPartition(config, dml);
            return true;
        });
    }

获取配置取的tableConfig,最终导致解析执行的sql,还是同一个库中同一张表,相当于同一个sql;陷入了死循环中。从tableConfig中取配置就可以解决,字段映射没测试,DDL语句未做处理,自行研究。初次学习canal,不知道这种使用场景对不对。 mirrorDbConfigCache中的mappingConfig与tableConfig两者的区别是啥?

mercilessly avatar Jul 04 '23 07:07 mercilessly

我按标记的syncDml里调整,没有效果啊。是覆盖plugins目录下的那个jar包吗?

egBean avatar Feb 20 '24 09:02 egBean