[alibaba/canal]当设置mirrorDb: true整库映射,全量同步的接口会报错

2025-11-13 749 views
1

这是我的mytest_user.yml配置文件,canal-adapter-1.1.5

#dataSourceKey: defaultDS
#destination: example
#groupId: g1
#outerAdapterKey: mysql1
#concurrent: true
#dbMapping:
#  database: mytest
#  table: user
#  targetTable: mytest2.user
#  targetPk:
#    id: id
##  mapAll: true
#  targetColumns:
#    id:
#    name:
#    role_id:
#    c_time:
#    test1:
#  etlCondition: "where c_time>={}"
#  commitBatch: 3000 # 批量提交的大小

## Mirror schema synchronize config
dataSourceKey: defaultDS
destination: myInstance
groupId: g1
outerAdapterKey: mysql1
concurrent: true
dbMapping:
  mirrorDb: true
  database: my-test
  commitBatch: 1000

设置mirrorDb: true为整库映射,当我执行全量同步的接口会报错, curl http://127.0.0.1:8081/etl/hbase/mysql1/mytest_person2.yml -X POST -d "params=2018-10-21 00:00:00" 报错信息:

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-test.null) _CNT' at line 1
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_102]
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_102]
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_102]
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_102]
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:425) ~[mysql-connector-java-5.1.48.jar:5.1.48]
    at com.mysql.jdbc.Util.getInstance(Util.java:408) ~[mysql-connector-java-5.1.48.jar:5.1.48]
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:944) ~[mysql-connector-java-5.1.48.jar:5.1.48]
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3933) ~[mysql-connector-java-5.1.48.jar:5.1.48]
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3869) ~[mysql-connector-java-5.1.48.jar:5.1.48]
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2524) ~[mysql-connector-java-5.1.48.jar:5.1.48]
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2675) ~[mysql-connector-java-5.1.48.jar:5.1.48]
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2465) ~[mysql-connector-java-5.1.48.jar:5.1.48]
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1912) ~[mysql-connector-java-5.1.48.jar:5.1.48]
    at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2020) ~[mysql-connector-java-5.1.48.jar:5.1.48]
    at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java:227) ~[druid-1.2.6.jar:1.2.6]
    at com.alibaba.otter.canal.client.adapter.support.Util.sqlRS(Util.java:59) ~[classes/:na]

将源码拉下来,本地debug发现,RdbEtlService.importData(List params) 这个方法好像有点问题:

/**
     * 导入数据
     */
    public EtlResult importData(List<String> params) {
        DbMapping dbMapping = config.getDbMapping();
        String sql = "SELECT * FROM " + dbMapping.getDatabase() + "." + dbMapping.getTable();
        return importData(sql, params);
    }

这里既然是整表映射,那么 dbMapping.getTable()必然是拿不到值的,拼接的sql肯定会有问题。肯定会报错,难道整表映射就不支持全量同步接口?

回答

2

根据我自己的测试,虽然mirrorDB=true的时候,增量同步已经是按库同步了,但如果想要用全量同步工具,就必须按table编写yml文件。也就是说,要专门为全量同步工具写一个表级别的yml文件。

另外,从同步原理来说,更新数据一定要知道PK是啥,那么就必须是按表来描述的。

1

因为业务需求同步两边的库名和名表也是一样的。于是我想用mirrorDB=true按库同步,目的就是不想一个个表的写yml文件,假设同步的表有很多,此时俺库同步应该是最佳选择

4

我测下来canal并不会识别PK然后自动按PK做同步,所以估计还是得自己写yml文件,当然也可以自己弄个脚本批量创建yml。

另外我们在实际使用中发现,canal在做大表ddl同步的时候有可能会因为sql执行超时而认为语句执行失败,然后就重试它。大的DDL一般来说总是超时的,就会卡队列。 我不太熟悉druid,要是您知道怎么修改它的执行超时时间,望不吝赐教

0

这个问题,一定要写所有表的yml吗?有更好的解决方案吗?

6

我mirrorDb: true时,从 数据库aa同步到 aa_1都不支持, 害得改源码。。 全量同步准备手动 nav icat导一下