1. 程式人生 > >不當事務程式碼引起的資料庫死鎖問題

不當事務程式碼引起的資料庫死鎖問題

錯誤案例

DBA反映IBANK線上資料庫報警,檢測到死鎖,跟蹤到發生死鎖等待的兩條SQL語句分別為:

UPDATE WP_IMAGE_SORT SET GMT_MODIFIED = SYSDATE,IMAGE_IDS = #imageIds# || IMAGE_IDS WHERE MEMBER_ID = #memberId# AND ALBUM_ID = #albumId#

以及

update WP_ALBUM set GMT_MODIFIED = sysdate, image_count = (select count(*) from wp_image where album_id= #id# and STATUS <![CDATA[<>]]> 'deleted') where id = #id# and member_id = #memberId#

錯誤分析

死鎖一般是由於資源互相佔用並且無法釋放導致的,因此重點排查IBANK中相關資料表的操作,發現在saveImg和moveImg兩個方法中存在以下邏輯

saveImg: { 
    ……
     //Transaction start
    imageBO.appendImageSort(memberId, album.getId(), imgId.longValue());
    ……
    winportAlbumDAO.updateAlbumImageCountAndLastModified(album.getId(), album.getMemberId());
    //Transaction end
   ……
} 
moveImg: { 
    ……
     //Transaction start
    winportAlbumDAO.updateAlbumImageCount(srcAlbumDO.getId(), memberId);
    ……
    imageBO.appendImageSort(memberId, targetAlbumDO.getId(), ids);
    //Transaction end
    ……
}

兩個事務的處理程式碼順序正好相反,相反的更新動作導致了死鎖。
死鎖的四要素:
互斥條件
請求與保持條件
不剝奪條件
迴圈等待條件
可以看出,前三條的都是事務引起的,因此大家以後要慎用事務處理或者設定事務級別,在確實需要使用 事務的時候,請打破迴圈條件(保持update語句呼叫順序的一致性,而非首尾相連的顛倒次序)

注:
這裡的問題簡單了說,就是需要保持一致的更新順序,比如
操作一:按順序更新,A,B,C
操作二:按順序更新,C,B,D
這樣就有可能會導致,B,C和C,B這兩個操作互相等待,導致死鎖

處理方法很簡單,把操作二變成B,C,D,因為兩個操作都需要獲得B,C這兩把鎖才能完成, 現在順序調整成一致
就能保證如果拿到B這把鎖,就能保證拿到C,完成事務,這樣就不會導致兩個操作互相等待了

支付寶曾經也出現過類似的問題的,在轉帳的時候會涉及到兩個帳號,也可能造成類似的互相等待的問題,
解決就是總是先鎖帳號ID小的那個,即“保持update語句呼叫順序的一致性”