5 分鐘理解數(shù)據(jù)庫死鎖

作者: 不剪發(fā)的Tony老師
畢業(yè)于北京航空航天大學,十多年數(shù)據(jù)庫管理與開發(fā)經(jīng)驗,目前在一家全球性的金融公司從事數(shù)據(jù)庫架構設計。CSDN學院簽約講師以及GitChat專欄作者。csdn上的博客收藏于以下地址:https://tonydong.blog.csdn.net

文章目錄

        死鎖是如何產(chǎn)生的?
        如何解決并避免死鎖
        總結

    ??知人者智,自知者明。勝人者有力,勝己者強。知足者富,強行者有志。不失其所者久,死而不亡者壽?!献?/p>

大家好!我是只談技術不剪發(fā)的 Tony 老師。

加鎖(Locking)是數(shù)據(jù)庫在并發(fā)訪問時保證數(shù)據(jù)一致性和完整性的主要機制。任何事務都需要獲得相應對象上的鎖才能訪問數(shù)據(jù),讀取數(shù)據(jù)的事務通常只需要獲得讀鎖(共享鎖),修改數(shù)據(jù)的事務需要獲得寫鎖(排他鎖)。當兩個事務互相之間需要等待對方釋放獲得的資源時,如果系統(tǒng)不進行干預則會一直等待下去,也就是進入了死鎖(deadlock)狀態(tài)。

本文給大家演示一下死鎖產(chǎn)生的場景和解決方法,如果覺得文章有用,歡迎評論??、點贊??、推薦??

    以下內(nèi)容適用于各種常見的數(shù)據(jù)庫管理系統(tǒng),包括 Oracle、MySQL、Microsoft SQL Server 以及 PostgreSQL 等。

死鎖是如何產(chǎn)生的?

演示死鎖的產(chǎn)生非常簡單,我們只需要創(chuàng)建一個包含兩行數(shù)據(jù)的簡單示例表:

CREATE TABLE t_lock(id int PRIMARY KEY, col int);
INSERT INTO t_lock VALUES (1, 100);
INSERT INTO t_lock VALUES (2, 200);

SELECT * FROM t_lock;
id|col|
--+---+
 1|100|
 2|200|

 

如果我們在不同事務中以不同的順序修改數(shù)據(jù),就可能引起事務之間的相互等待。一個事務等待另一個事務釋放資源不會產(chǎn)生什么問題,但是如果兩個事務互相等待對方的資源,數(shù)據(jù)庫管理系統(tǒng)只有兩個選擇:無限等待或者中止一個事務并讓另一個事務成功執(zhí)行。

顯然無限等待不是解決問題的方法,因此數(shù)據(jù)庫通常是等待一定時間之后中止其中一個事務。

以下是一個死鎖的演示案例:
 

對于 MySQL InnoDB,默認啟用了 innodb_deadlock_detect 選項,事務二返回以下錯誤信息:

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

    1

如果我們禁用 InnoDB 死鎖檢測選項,事務二在等待 50 s(innodb_lock_wait_timeout )后提示等待超時:

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

 

Oracle 檢測到死鎖時返回以下錯誤:

ORA-00060: 等待資源時檢測到死鎖

 

Microsoft SQL Server 檢測到死鎖時返回的錯誤如下

消息 1205,級別 13,狀態(tài) 51,第 7 行
事務(進程 ID 67)與另一個進程被死鎖在 鎖 資源上,并且已被選作死鎖犧牲品。請重新運行該事務。

 

PostgreSQL 檢測到死鎖時返回的錯誤如下:

SQL 錯誤 [40P01]: 錯誤: 檢測到死鎖
  詳細:進程32等待在事務 4765上的ShareLock; 由進程16552阻塞.
進程16552等待在事務 4766上的ShareLock; 由進程32阻塞.
  建議:詳細信息請查看服務器日志.
  在位置:當更新關系"t_lock"的元組(0, 1)時

 

如何解決并避免死鎖

死鎖不是數(shù)據(jù)庫自身的問題,我們無法通過優(yōu)化數(shù)據(jù)庫配置來解決或者避免死鎖,只能通過修改應用程序來解決。簡單來說,我們應該在程序中按照相同的順序修改數(shù)據(jù),避免產(chǎn)生相互等待資源的情況發(fā)生。例如:
 

以上場景不會產(chǎn)生死鎖。不過,我們在實際應用中可能無法完全按照相同順序修改數(shù)據(jù)。如果出現(xiàn)了不可避免的死鎖情況,另一種解決方法就是捕獲系統(tǒng)返回的死鎖異常并在程序中加入重試機制。

總結

本文簡要介紹了數(shù)據(jù)庫死鎖產(chǎn)生的原因和解決方法。