首先我們設(shè)想一個情況胁附,然后來闡述今天的問題:現(xiàn)在有若干臺服務(wù)器,用相同的接口去批量修改一批數(shù)據(jù)滓彰,但是數(shù)據(jù)中彼此有重復(fù)的數(shù)據(jù)汉嗽。基于這個問題找蜜,出現(xiàn)下面這種情況的死鎖-->
?
?
?
?
?
問題分析:因為1服務(wù)器修改的批次包括abcdef 這個時候剛好修改了abcd所以abcd的索引被鎖住了饼暑,2服務(wù)器修改了efgh,這個時候efgh的索引被鎖住了
?
因為批量修改是一個默認(rèn)的事務(wù)洗做,所以如果沒有全部修改完弓叛,索引是不會被放開的,所以1服務(wù)器的e等待2服務(wù)器放開诚纸,2服務(wù)器的c等待1服務(wù)器放開撰筷,造成死鎖。畦徘。毕籽。。井辆。
?
解決辦法1:將批量修改通過for循環(huán)改成單條修改关筒,但是這個方法對服務(wù)器的壓力增大
?
解決辦法2:我們在獲取數(shù)據(jù)的時候進(jìn)行一次篩選,將重復(fù)的數(shù)據(jù)剔除出去杯缺,我們用到了redis
?
再用redis分布式鎖蒸播,進(jìn)行批量更新。這樣的好處就是解決問題的同時減少對服務(wù)器的壓力
?
具體操作看代碼
?
?
public int batch(SmsReport[] rpts) {
?? if (ArrayUtils.isEmpty(rpts)){
?????? return0;
?? }
??? 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的有效時間設(shè)為若干分鐘,通過key唯一的性質(zhì)進(jìn)行數(shù)據(jù)排重袍榆,這樣即使是多線程多服務(wù)器進(jìn)行批量修改胀屿,也可以整合成一次數(shù)據(jù)無重復(fù)的批量修改蛾魄,從而解決重復(fù)數(shù)據(jù)的死鎖問題召耘。。髓削。才写。劳曹。
?
?