首先我们设想一个情况,然后来阐述今天的问题:现在有若干台服务器,用相同的接口去批量修改一批数据,但是数据中彼此有重复的数据。基于这个问题,出现下面这种情况的死锁–>
问题分析:因为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唯一的性质进行数据排重,这样即使是多线程多服务器进行批量修改,也可以整合成一次数据无重复的批量修改,从而解决重复数据的死锁问题。。。。。
问题扩展:上面是批量修改造成的死锁,还有就是多线程单条数据造成的死锁,就是两个线程同时修改一条数据,彼此拿到了各自的非主键索引,导致非主键索引不全造成的死锁,这个问题关注我在下一篇文章分享。
版权声明:本文为qq_36005199原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。