首頁>技術>

透過sql查詢

select * from information_schema.innodb_trx;

我們發現是更新表sys_sn_rule導致的,那麼我們理一下程式碼,看看為什麼會出現LOCK_WAIT。

原因排查

透過檢視介面呼叫,我們定位到一個方法上,這裡我將方法簡化。簡化後的程式碼如下:

@Override@Transactional(rollbackFor = Exception.class)public Result funA() {    //更新表table1;    funB();    ...}public void funB() {   //更新表table1;   ....}

問題就出在,funA呼叫了funB,而兩個方法同時操作了表table1上的同一條資料。這裡會有兩個事務,在更新資料時,會產生兩個事務都在互相等待對方關閉事務,從而到時死鎖。我們來作圖說明下:

如上圖,執行funA時,會執行更新表table1,更新表前會開啟事務A,更新表時會給這行資料上鎖(為了保護資料的一致性)。接下來呼叫funB,開啟事務B,更新表table1,因為表table1的這行已經鎖住了,所以事務B中需要等鎖釋放才能繼續執行。但是事務A要想關閉,需要等funA執行完才能關閉。而funA中呼叫了funB,funB要等待table1釋放鎖才能執行完。這樣就導致了死迴圈。

關於資料庫加鎖的知識,可以看看這篇文章:

解決死鎖之路 - 學習事務與隔離級別 - aneasystone's blog

(https://www.aneasystone.com/archives/2017/10/solving-dead-locks-one.html)

解決辦法

我們可以採用多執行緒解決:

@Override@Transactional(rollbackFor = Exception.class)public Result funA() {    //更新表table1;    taskExecutor.execute(() -> {        try {            Thread.sleep(5 * 1000);            funB();        } catch (InterruptedException e) {            e.printStackTrace();        }    });    ...}public void funB() {   //更新表table1;   ....}

採用多執行緒,兩個事務就分別在兩個不同的執行緒裡面了,就不會出現迴圈等待的情況。

程式碼修改後,測試順利透過。

11
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 清華教授用了10小時講完的前端教程,整整400集,拿走不謝