otter二次开发-支持按目标端主键索引Load数据
# 一、背景
由于表主键按id自增,使用分库分表后,分库的表会出现主键相同的情况,在使用otter往下游数据同步,合并成一张表的过程中会导致数据异常,解决办法是将下游的表改成联合主键索引,按照下游表的主键索引进行更新数据。但是otter是按照源端的主键索引load数据的,因此对otter进行二次开发,使其支持目标端主键索引Load数据
# 二、按目标端主键索引Load数据支持
基于otter-4.2.18 (opens new window)改造
完整代码提交记录:https://github.com/HeyouA/otter/commit/2e41b69f0601196f122c4aa3dd8609d4f6e9149c
# 三、FAQ
# 3.1、数据合并时(insert+delete)合并失败导致下游数据未删除问题
业务背景:支持按目标端主键索引Load数据上线后,一个月后,用户反馈报表数据重复,分析后发现下游数据存在少量重复问题
问题原因
定位问题后发现,部分业务存在事务A先插入后立马在事务B删除这条数据的场景,示例代码如下
@Service
public class TestServiceImpl extends ServiceImpl<UserMapper, User> implements ITestService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void testOtter(User entity) {
this.save(entity);
this.delUser(entity.getId());
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void delUser(Integer id) {
this.removeById(id);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
otter在load数据时会按table+pk进行数据合并(insert + delete = delete),而我们的支持按目标端主键索引Load数据功能,只有主键变更或者删除才会重新定义pk,导致合并数据失败,有较低的概率出现删除失败的问题。代码片段如下:
.
.
.
//重新定义pk字段和其它字段
//只有主键变更或者删除才需要重新定义,使用目标表的主键索引
List<EventColumn> columns = data.getColumns();
List<EventColumn> keys = data.getKeys();
List<EventColumn> oldKeys = data.getOldKeys();
boolean existOldKeys = !CollectionUtils.isEmpty(data.getOldKeys());//主键变更
boolean isDelete = data.getEventType().isDelete();//删除
if (existOldKeys || isDelete) {
List<EventColumn> allSourceColumns = new ArrayList<>();//源表所有字段
allSourceColumns.addAll(keys);
allSourceColumns.addAll(columns);
.
.
.
.
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
解决方法
放开insert限制即可