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

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


文章目錄

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

??知人者智,自知者明。勝人者有力,勝己者強(qiáng)。知足者富,強(qiáng)行者有志。不失其所者久,死而不亡者壽?!献?
  • 1
  • 2
  • 3
  • 4
  • 5

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

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

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

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

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

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

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|

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

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

以下是一個(gè)死鎖的演示案例:
在這里插入圖片描述

對(duì)于 MySQL InnoDB,默認(rèn)啟用了 innodb_deadlock_detect 選項(xiàng),事務(wù)二返回以下錯(cuò)誤信息:

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

1
  • 1

如果我們禁用 InnoDB 死鎖檢測(cè)選項(xiàng),事務(wù)二在等待 50 s(innodb_lock_wait_timeout )后提示等待超時(shí):

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

1
  • 1

Oracle 檢測(cè)到死鎖時(shí)返回以下錯(cuò)誤:

ORA-00060: 等待資源時(shí)檢測(cè)到死鎖

1
  • 1

Microsoft SQL Server 檢測(cè)到死鎖時(shí)返回的錯(cuò)誤如下

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

PostgreSQL 檢測(cè)到死鎖時(shí)返回的錯(cuò)誤如下:

SQL 錯(cuò)誤 [40P01]: 錯(cuò)誤: 檢測(cè)到死鎖
詳細(xì):進(jìn)程32等待在事務(wù) 4765上的ShareLock; 由進(jìn)程16552阻塞.
進(jìn)程16552等待在事務(wù) 4766上的ShareLock; 由進(jìn)程32阻塞.
建議:詳細(xì)信息請(qǐng)查看服務(wù)器日志.
在位置:當(dāng)更新關(guān)系"t_lock"的元組(0, 1)時(shí)

如何解決并避免死鎖

死鎖不是數(shù)據(jù)庫(kù)自身的問(wèn)題,我們無(wú)法通過(guò)優(yōu)化數(shù)據(jù)庫(kù)配置來(lái)解決或者避免死鎖,只能通過(guò)修改應(yīng)用程序來(lái)解決。簡(jiǎn)單來(lái)說(shuō),我們應(yīng)該在程序中按照相同的順序修改數(shù)據(jù),避免產(chǎn)生相互等待資源的情況發(fā)生。例如:
在這里插入圖片描述

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

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