1. 报错日志
pid:2 nid:1 exception:canal:canal4:com.alibaba.otter.canal.parse.exception.CanalParseException: java.lang.NoSuchFieldError: MYSQL
Caused by: java.lang.NoSuchFieldError: MYSQL
at com.alibaba.otter.canal.parse.inbound.mysql.ddl.DruidDdlParser.parse(DruidDdlParser.java:51)
at com.alibaba.otter.canal.parse.inbound.mysql.dbsync.LogEventConvert.parseQueryEvent(LogEventConvert.java:258)
at com.alibaba.otter.canal.parse.inbound.mysql.dbsync.LogEventConvert.parse(LogEventConvert.java:120)
at com.alibaba.otter.canal.parse.inbound.mysql.dbsync.LogEventConvert.parse(LogEventConvert.java:71)
at com.alibaba.otter.canal.parse.inbound.AbstractEventParser.parseAndProfilingIfNecessary(AbstractEventParser.java:414)
at com.alibaba.otter.canal.parse.inbound.AbstractEventParser$1$1.sink(AbstractEventParser.java:214)
at com.alibaba.otter.canal.parse.inbound.mysql.MysqlConnection.dump(MysqlConnection.java:185)
at com.alibaba.otter.canal.parse.inbound.AbstractEventParser$1.run(AbstractEventParser.java:276)
at java.lang.Thread.run(Thread.java:748)
2. 原因分析
java.lang.NoSuchFieldError
通常是访问了某个类不存在的成员变量,可能是代码没编译更新,或者使用了不同版本的依赖。
在Otter这里是使用了不同的 Druid 版本。
Canal 1.1.5中 Druid版本为1.2.6,Otter中被改为了1.1.9。
3. 解决办法
有2个步骤,亲测有效:
1 修改Druid版本
otter项目最外层的pom文件194行
<version>1.1.9</version>
改成 <version>1.2.6</version>
2 更新代码
bash
// 130行
if (x.isIfNotExiists()) {
print0(ucase ? "IF NOT EXISTS " : "if not exists ");
}
// 改成(拼写错误)
if (x.isIfNotExists()) {
print0(ucase ? "IF NOT EXISTS " : "if not exists ");
}
bash
// 158行 239行
for (Map.Entry<String, SQLObject> option : x.getTableOptions().entrySet()) {
String key = option.getKey();
...
// 改成(方法改变)
for (SQLAssignItem option : x.getTableOptions()) {
String key = ((SQLIdentifierExpr) option.getTarget()).getName();
...
需要注意:
1 文件位置: node/etl/src/main/java/com/alibaba/otter/node/etl/common/db/utils/DdlUtils.java
2 需要 import com.alibaba.druid.sql.ast.statement.SQLAssignItem;
可以参考 github issue