多線程update批量更新造成的死鎖,問(wèn)題分析和解決辦法

首先我們?cè)O(shè)想一個(gè)情況,然后來(lái)闡述今天的問(wèn)題:現(xiàn)在有若干臺(tái)服務(wù)器,用相同的接口去批量修改一批數(shù)據(jù),但是數(shù)據(jù)中彼此有重復(fù)的數(shù)據(jù)?;谶@個(gè)問(wèn)題,出現(xiàn)下面這種情況的死鎖-->

?

?

?

?

?

問(wèn)題分析:因?yàn)?服務(wù)器修改的批次包括abcdef 這個(gè)時(shí)候剛好修改了abcd所以abcd的索引被鎖住了,2服務(wù)器修改了efgh,這個(gè)時(shí)候efgh的索引被鎖住了

?

因?yàn)榕啃薷氖且粋€(gè)默認(rèn)的事務(wù),所以如果沒(méi)有全部修改完,索引是不會(huì)被放開(kāi)的,所以1服務(wù)器的e等待2服務(wù)器放開(kāi),2服務(wù)器的c等待1服務(wù)器放開(kāi),造成死鎖。。。。。

?

解決辦法1:將批量修改通過(guò)for循環(huán)改成單條修改,但是這個(gè)方法對(duì)服務(wù)器的壓力增大

?

解決辦法2:我們?cè)讷@取數(shù)據(jù)的時(shí)候進(jìn)行一次篩選,將重復(fù)的數(shù)據(jù)剔除出去,我們用到了redis

?

再用redis分布式鎖,進(jìn)行批量更新。這樣的好處就是解決問(wèn)題的同時(shí)減少對(duì)服務(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í)間設(shè)為若干分鐘,通過(guò)key唯一的性質(zhì)進(jìn)行數(shù)據(jù)排重,這樣即使是多線程多服務(wù)器進(jìn)行批量修改,也可以整合成一次數(shù)據(jù)無(wú)重復(fù)的批量修改,從而解決重復(fù)數(shù)據(jù)的死鎖問(wèn)題。。。。。

?

?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容