环境信息
canal version canal-adapter1.1.3-alpha-2 mysql version mysql
问题描述
在两张表join的时候,如果两张表有同名列名,在update的时候,会错误更新两个字段 表A:school_phase 有一个字段是phase_code 表B:school 有一个字段也是phase_code 表A和表B left join的时候 把表a的phase_code 命名为 school_phase_code,表b的还是phase_code 但是测试在测试的过程发现,更新表A的phase_code 会也把es索引里的phase_code也更新了
现执行情况
这边看了下代码是
public Object getESDataFromDmlData(ESMapping mapping, Map<String, Object> dmlData, Map<String, Object> dmlOld, Map<String, Object> esFieldData)
这个函数有问题,里面
if (dmlOld.containsKey(columnName) && !mapping.getSkips().contains(fieldItem.getFieldName())) { esFieldData.put(Util.cleanColumn(fieldItem.getFieldName()), getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName)); }
没有考虑表的关系,我这边是重新了这段逻辑,在判断更新的时候,加了一段判断是否是同一张表
//处理两张表字段同名的bug String aliceTableName = mapping.getSchemaItem().getAliasesName(tableName); if(StringUtils.isNotEmpty(aliceTableName)){
for ( Map.Entry<String, FieldItem> fieldItemEntry : schemaItem.getSelectFields().entrySet()) {
FieldItem fieldItem =fieldItemEntry.getValue();
String ownTable = fieldItem.getOwner();
String columnName = fieldItem.getColumnItems().iterator().next().getColumnName();
String aliceColumnName = fieldItemEntry.getKey();
if (fieldItem.getFieldName().equals(idFieldName)) {
resultIdVal = getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName);
}
if (StringUtils.equals(ownTable,aliceTableName) && dmlOld.get(columnName) != null && !mapping.getSkips().contains(fieldItem.getFieldName())) {
esFieldData.put(fieldItem.getFieldName(),
getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName));
}
}
}else{
for (FieldItem fieldItem : schemaItem.getSelectFields().values()) {
String columnName = fieldItem.getColumnItems().iterator().next().getColumnName();
if (fieldItem.getFieldName().equals(idFieldName)) {
resultIdVal = getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName);
}
if (dmlOld.get(columnName) != null && !mapping.getSkips().contains(fieldItem.getFieldName())) {
esFieldData.put(fieldItem.getFieldName(),
getValFromData(mapping, dmlData, fieldItem.getFieldName(), columnName));
}
}
}
return resultIdVal;
}
原提问者GitHub用户house0128
针对这个问题,建议尝试以下几种解决方案:
修改表结构,避免同名字段 根据您的描述,表 A 和表 B 中均有一个同名的 phase_code 字段。建议修改表结构,将这两个字段命名为不同的名称,避免出现同名字段导致的数据更新错误。
修改 CanalAdapter 代码,增加字段前缀或后缀 如果您无法修改表结构,可以考虑修改 CanalAdapter 的代码,在处理 join 操作时增加相应的字段前缀或后缀。例如,可以将表 A 的 phase_code 字段更名为 school_phase_code,将表 B 的 phase_code 字段更名为 school_code_phase 等。这样可以确保每个字段的唯一性,避免出现同名字段导致的更新错误。
使用 Canal 的 interceptors 功能 Canal 提供了 interceptors 功能,可以在数据变更事件到达 Canal 内部之前对其进行拦截和修改。您可以编写一个自定义的 interceptor,在处理 join 操作时检测同名字段,并将其更名为唯一的名称。例如,可以将表 A 的 phase_code 字段更名为 school_phase_code,将表 B 的 phase_code 字段更名为 school_code_phase 等。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。