程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> 關於MYSQL數據庫 >> InnoDB數據庫死鎖問題處理

InnoDB數據庫死鎖問題處理

編輯:關於MYSQL數據庫

場景描述

在update表的時候出現DeadlockLoserDataAccessException異常 (Deadlock found when trying to get lock; try restarting transaction...)。

問題分析

這個異常並不會影響用戶使用,因為數據庫遇到死鎖會自動回滾並重試。用戶的感覺就是操作稍有卡頓。但是監控老是報異常,所以需要解決一下。

解決方法

在應用程序中update的地方使用try-catch。

我自己封裝了一個函數,如下。

/**
   * 2016-03-15
   * linxuan
   * handle deadlock while update table
   */
  private void updateWithDeadLock(TestMapper mapper, Test record) throws InterruptedException {
    boolean oops;
    int retries = 5;
    do{
      oops = false;
      try{
        mapper.updateByPrimaryKeySelective(record);
      }
      catch (DeadlockLoserDataAccessException dlEx){
        oops = true;
        Thread.sleep((long) (Math.random() * 500));
      }
      finally {
      }
    } while(oops == true && retries-- >0);
  }

我用的是mybatis,所以只需將mapper傳進函數,如果不用mybatis,需要自己創建並關閉數據庫連接。

延伸:數據庫死鎖

數據庫死鎖是事務性數據庫 (如SQL Server, MySql等)經常遇到的問題。除非數據庫死鎖問題頻繁出現導致用戶無法操作,一般情況下數據庫死鎖問題不嚴重。在應用程序中進行try-catch就可以。那麼數據死鎖是如何產生的呢?

InnoDB實現的是行鎖 (row level lock),分為共享鎖 (S) 和 互斥鎖 (X)。

共享鎖用於事務read一行。
互斥鎖用於事務update或delete一行。
當客戶A持有共享鎖S,並請求互斥鎖X;同時客戶B持有互斥鎖X,並請求共享鎖S。以上情況,會發生數據庫死鎖。如果還不夠清楚,請看下面的例子。

數據庫死鎖例子

首先,客戶A創建一個表T,並向T中插入一條數據,客戶A開始一個select事務,所以拿著共享鎖S。

mysql> CREATE TABLE t (i INT) ENGINE = InnoDB;
Query OK, 0 rows affected (1.07 sec)

mysql> INSERT INTO t (i) VALUES(1);
Query OK, 1 row affected (0.09 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM t WHERE i = 1 LOCK IN SHARE MODE;
+------+
| i  |
+------+
|  1 |
+------+

然後,客戶B開始一個新事務,新事務是delete表T中的唯一一條數據。

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> DELETE FROM t WHERE i = 1;

刪除操作需要互斥鎖 (X),但是互斥鎖X和共享鎖S是不能相容的。所以刪除事務被放到鎖請求隊列中,客戶B阻塞。

最後,客戶A也想刪除表T中的那條數據:

mysql> DELETE FROM t WHERE i = 1;
ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction

死鎖產生了!因為客戶A需要鎖X來刪除行,而客戶B拿著鎖X並正在等待客戶A釋放鎖S。看看客戶A,B的狀態:

客戶A: 拿著鎖S,等待著客戶B釋放鎖X。
客戶B: 拿著鎖X,等待著客戶A釋放鎖S。

發生死鎖後,InnoDB會為對一個客戶產生錯誤信息並釋放鎖。返回給客戶的信息:

ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction
所以,另一個客戶可以正常執行任務。死鎖結束。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved