canal-adpter执行update语句durid报错parse sql error解决方法

项目使用canal-adapter进行数据同步时遇到SQL错误,原因在于目标表未设置主键,adapter尝试根据主键拼接WHERE子句时出错。解决方案是在相关表中添加主键。
摘要由CSDN通过智能技术生成

项目场景:

提示:这里简述项目相关背景:

canal-adpter在执行update同步数据时报错


问题描述

提示:这里描述项目中遇到的问题:

例如:从这里可以看出update时sql补全,出现了WH无法识别的问题,看起来是在拼接WHERE关键字时被截取了。

2024-04-22 11:20:41.572 [Thread-11] ERROR c.a.otter.canal.adapter.launcher.loader.AdapterProcessor - Outer adapter sync failed!  Error sync and rollb
ack, execute times: 1880803
2024-04-22 11:20:42.076 [pool-29-thread-1] ERROR com.alibaba.druid.filter.stat.StatFilter - merge sql error, dbType mysql, druid-1.2.17, sql : UPDATE `mytest`.`t` SET `id`=? WH
com.alibaba.druid.sql.parser.ParserException: not supported.pos 33, line 1, column 31, token IDENTIFIER WH
        at com.alibaba.druid.sql.parser.SQLStatementParser.parseStatementList(SQLStatementParser.java:615)
        at com.alibaba.druid.sql.parser.SQLStatementParser.parseStatementList(SQLStatementParser.java:101)
        at com.alibaba.druid.sql.visitor.ParameterizedOutputVisitorUtils.parameterize(ParameterizedOutputVisitorUtils.java:163)
        at com.alibaba.druid.sql.visitor.ParameterizedOutputVisitorUtils.parameterize(ParameterizedOutputVisitorUtils.java:134)
        at com.alibaba.druid.filter.stat.StatFilter.mergeSql(StatFilter.java:148)
        at com.alibaba.druid.filter.stat.StatFilter.createSqlStat(StatFilter.java:672)
        at com.alibaba.druid.filter.stat.StatFilter.statementPrepareAfter(StatFilter.java:325)
        at com.alibaba.druid.filter.FilterEventAdapter.connection_prepareStatement(FilterEventAdapter.java:118)
        at com.alibaba.druid.filter.FilterChainImpl.connection_prepareStatement(FilterChainImpl.java:531)
        at com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl.prepareStatement(ConnectionProxyImpl.java:326)
        at com.alibaba.druid.pool.DruidPooledConnection.prepareStatement(DruidPooledConnection.java:362)
        at com.alibaba.otter.canal.client.adapter.rdb.support.BatchExecutor.execute(BatchExecutor.java:55)
        at com.alibaba.otter.canal.client.adapter.rdb.service.RdbSyncService.update(RdbSyncService.java:365)
        at com.alibaba.otter.canal.client.adapter.rdb.service.RdbSyncService.sync(RdbSyncService.java:228)
        at com.alibaba.otter.canal.client.adapter.rd

原因分析:

直接说结论和解决方法:

原因是因为同步的表没有设置主键,而canal-adapter在同步的时候,是根据主键去拼接where条件的,如果没有设置会导致截取出错。
下面是源代码

com.alibaba.otter.canal.client.adapter.rdb.service.RdbSyncService

 private void appendCondition(MappingConfig.DbMapping dbMapping, StringBuilder sql, Map<String, Integer> ctype,
                                 List<Map<String, ?>> values, Map<String, Object> d, Map<String, Object> o) {
        String backtick = SyncUtil.getBacktickByDbType(dataSource.getDbType());

        // 拼接主键
        for (Map.Entry<String, String> entry : dbMapping.getTargetPk().entrySet()) {
            String targetColumnName = entry.getKey();
            String srcColumnName = entry.getValue();
            if (srcColumnName == null) {
                srcColumnName = Util.cleanColumn(targetColumnName);
            }
            sql.append(backtick).append(targetColumnName).append(backtick).append("=? AND ");
            Integer type = ctype.get(Util.cleanColumn(targetColumnName).toLowerCase());
            if (type == null) {
                throw new RuntimeException("Target column: " + targetColumnName + " not matched");
            }
            // 如果有修改主键的情况
            if (o != null && o.containsKey(srcColumnName)) {
                BatchExecutor.setValue(values, type, o.get(srcColumnName));
            } else {
                BatchExecutor.setValue(values, type, d.get(srcColumnName));
            }
        }
        /**
        * 关键是在这里
        * 如果没有主键会直接运行这段代码
        * 拼接好的WHERE会被截取掉后4个字符变成 WH
        **/
        int len = sql.length();
        sql.delete(len - 4, len);
    }

解决方案:

给相关的表添加主键即可解决

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值