多线程update批量更新造成的死锁,问题分析和解决办法

首先我们设想一个情况,然后来阐述今天的问题:现在有若干台服务器,用相同的接口去批量修改一批数据,但是数据中彼此有重复的数据。基于这个问题,出现下面这种情况的死锁-->

 

问题分析:因为1服务器修改的批次包括abcdef 这个时候刚好修改了abcd所以abcd的索引被锁住了,2服务器修改了efgh,这个时候efgh的索引被锁住了

因为批量修改是一个默认的事务,所以如果没有全部修改完,索引是不会被放开的,所以1服务器的e等待2服务器放开,2服务器的c等待1服务器放开,造成死锁。。。。。

解决办法1:将批量修改通过for循环改成单条修改,但是这个方法对服务器的压力增大

解决办法2:我们在获取数据的时候进行一次筛选,将重复的数据剔除出去,我们用到了redis

再用redis分布式锁,进行批量更新。这样的好处就是解决问题的同时减少对服务器的压力

具体操作看代码


public int batch(SmsReport[] rpts) {
   if (ArrayUtils.isEmpty(rpts)) {
       return 0;
   }
    List<SmsReport> list = new ArrayList<>(Arrays.asList(rpts));
    Iterator<SmsReport> iterator = list.iterator();
    while(iterator.hasNext()){
       SmsReport rpt = iterator.next();//
            redisTemplate.delete(CACHE_KEY_REPORT_MEG_ID_PREFIX+rpt);
            if(redisTemplate.opsForValue().setIfAbsent(CACHE_KEY_REPORT_MEG_ID_PREFIX,"" )){
redisTemplate.expire(CACHE_KEY_REPORT_MEG_ID_PREFIX, 1 * 60, TimeUnit.SECONDS);
            } else{
                iterator.remove();
            }
        }
        if(list.isEmpty()){
            return 0;
        }
        return sendDataMapper.batch(list.toArray(new SmsReport[list.size()]));

    }

我们将redis的有效时间设为若干分钟,通过key唯一的性质进行数据排重,这样即使是多线程多服务器进行批量修改,也可以整合成一次数据无重复的批量修改,从而解决重复数据的死锁问题。。。。。

 

问题扩展:上面是批量修改造成的死锁,还有就是多线程单条数据造成的死锁,就是两个线程同时修改一条数据,彼此拿到了各自的非主键索引,导致非主键索引不全造成的死锁,这个问题关注我在下一篇文章分享。

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值