【项目问题定位】多线程处理文件数据去重的一点探讨

问题背景

系统中有个定时任务,会处理一些其它系统送来的文件。
它会批量扫描这些文件中各行数据并记录入表。
业务上要求数据库记录字段KEY需要唯一,如果已有记录则不处理文件中对应内容。

所以代码中最开始的校重逻辑实现是:
处理前先查库中是否有已存在KEY=文件记录的,不存在才insert。
伪代码如下:

dto = DAO.SelectByKey(key);
// 判断是否已存在
if (dto == null) {
    insert();
}
 // 已经相同KEY数据,不再入表
else {
    dealRepeater();
}

上面代码在单线程下没有问题。
但是后来为了提升性能改造成了多线程并发处理,那么上面校重逻辑就失效了。
(线程A先处理,发现库中无该KEY数据,则insert,但在A事务提交前,线程B也进行了处理,查询发现库中无该KEY数据,所以也会insert。最终库中就有了两条相同KEY的数据。)
这是很典型的并发去重问题。那么如何解决呢?

问题解决探讨

1.利用唯一索引

将该表KEY字段设置为唯一性索引,尝试insert。如果抛出“违反唯一性约束异常”,则表示已有重复数据。
伪代码如下:

if (dto != null) {  
    // 已经相同KEY数据,不再入表
    dealRepeater();
} else {   
    try {  
        insert();  
        //违反唯一性约束会报异常:InvocationTargetException 
    } catch (InvocationTargetException e) {  
        //说明重复插入,则不再入表
        dealRepeater();
    }   
}  

但这样处理的缺点在于:
- 1.需要新增索引;
- 2.通过异常来控制业务逻辑不符合规范。

2.带条件的INSERT

INSERT INTO IF EXISTS
伪代码如下:

INSERT INTO TABEL_NAME_A(ID, KEY, FILED3, ...) 
SELECT 'ID', 'KEY', 'FILED3', ... 
    FROM DUAL 
    WHERE NOT EXISTS(
      SELECT KEY
      FROM TABEL_NAME_A
      WHERE KEY= 'KEY')

但不同线程不同事务,可能仍然有问题?

3.文件预去重处理

即在定时任务业务处理逻辑之前增加预处理去重逻辑。
将文件内容进行去重处理,然后这样再多线程处理。
保证每一个线程处理的KEY各不相同。
缺点是不太适合此业务多文件间重复KEY的场景。

4.将错就错

由于目前这个定时任务A仅仅是将文件数据入表,实际业务处理在另一个定时任务B处理。那么我们可以将错就错,在B处理前增加去重逻辑。通过SQL查询出重复数据并删除。然后再进行处理。
SQL如下:

SELECT A.KEY
FROM TABLE_NAME A 
WHERE A.STATE = 'I'  // 待处理数据
GROUP BY A.KEY HAVING COUNT(A.KEY) > 1

这是我目前能想到的几种处理方法。
如果你有其他看法,不妨在评论区指点一下。不胜感激!!!

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伯子南

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值