5分鐘快速了解數(shù)據(jù)庫死鎖產(chǎn)生的場(chǎng)景和解決方法
前言
加鎖(Locking)是數(shù)據(jù)庫在并發(fā)訪問時(shí)保證數(shù)據(jù)一致性和完整性的主要機(jī)制。任何事務(wù)都需要獲得相應(yīng)對(duì)象上的鎖才能訪問數(shù)據(jù),讀取數(shù)據(jù)的事務(wù)通常只需要獲得讀鎖(共享鎖),修改數(shù)據(jù)的事務(wù)需要獲得寫鎖(排他鎖)。當(dāng)兩個(gè)事務(wù)互相之間需要等待對(duì)方釋放獲得的資源時(shí),如果系統(tǒng)不進(jìn)行干預(yù)則會(huì)一直等待下去,也就是進(jìn)入了死鎖(deadlock)狀態(tài)。
以下內(nèi)容適用于各種常見的數(shù)據(jù)庫管理系統(tǒng),包括 Oracle、MySQL、Microsoft SQL Server 以及 PostgreSQL 等。
死鎖是如何產(chǎn)生的?
演示死鎖的產(chǎn)生非常簡單,我們只需要?jiǎng)?chuàng)建一個(gè)包含兩行數(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|
如果我們?cè)诓煌聞?wù)中以不同的順序修改數(shù)據(jù),就可能引起事務(wù)之間的相互等待。一個(gè)事務(wù)等待另一個(gè)事務(wù)釋放資源不會(huì)產(chǎn)生什么問題,但是如果兩個(gè)事務(wù)互相等待對(duì)方的資源,數(shù)據(jù)庫管理系統(tǒng)只有兩個(gè)選擇:無限等待或者中止一個(gè)事務(wù)并讓另一個(gè)事務(wù)成功執(zhí)行。
顯然無限等待不是解決問題的方法,因此數(shù)據(jù)庫通常是等待一定時(shí)間之后中止其中一個(gè)事務(wù)。
以下是一個(gè)死鎖的演示案例:
事務(wù)一 | 事務(wù)二 | 備注 |
---|---|---|
BEGIN; | BEGIN; | 分別開始兩個(gè)事務(wù) |
UPDATE t_lock SET col = col + 100 WHERE id = 1; |
UPDATE t_lock SET col = col + 200 WHERE id = 2; |
事務(wù)一修改 id=1 的數(shù)據(jù),事務(wù)二修改 id=2 的數(shù)據(jù) |
UPDATE t_lock SET col = col + 100 WHERE id = 2; |
事務(wù)一修改 id=2 的數(shù)據(jù),需要等待事務(wù)二釋放寫鎖 | |
等待中… | UPDATE t_lock SET col = col + 200 WHERE id = 1; |
事務(wù)二修改 id=1 的數(shù)據(jù),需要等待事務(wù)一釋放寫鎖 |
死鎖 | 死鎖 | 數(shù)據(jù)庫檢測(cè)到死鎖,選擇中止一個(gè)事務(wù) |
更新成功 | 返回錯(cuò)誤 |
對(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
如果我們禁用 InnoDB 死鎖檢測(cè)選項(xiàng),事務(wù)二在等待 50 s(innodb_lock_wait_timeout )后提示等待超時(shí):
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
Oracle 檢測(cè)到死鎖時(shí)返回以下錯(cuò)誤:
ORA-00060: 等待資源時(shí)檢測(cè)到死鎖
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ù)庫自身的問題,我們無法通過優(yōu)化數(shù)據(jù)庫配置來解決或者避免死鎖,只能通過修改應(yīng)用程序來解決。簡單來說,我們應(yīng)該在程序中按照相同的順序修改數(shù)據(jù),避免產(chǎn)生相互等待資源的情況發(fā)生。例如:
事務(wù)一 | 事務(wù)二 | 備注 |
---|---|---|
BEGIN; | BEGIN; | 分別開始兩個(gè)事務(wù) |
UPDATE t_lock SET col = col + 100 WHERE id = 1; |
UPDATE t_lock SET col = col + 200 WHERE id = 1; |
事務(wù)一和事務(wù)二都修改 id=1 的數(shù)據(jù),后執(zhí)行的事務(wù)需要等待 |
UPDATE t_lock SET col = col + 100 WHERE id = 2; |
等待中… | 事務(wù)一修改 id=1 的數(shù)據(jù),事務(wù)二等待中 |
COMMIT; | 等待中… | 事務(wù)一提交 |
UPDATE t_lock SET col = col + 200 WHERE id = 2; |
事務(wù)二繼續(xù)修改 id=2 的數(shù)據(jù) | |
COMMIT; | 事務(wù)二提交 |
以上場(chǎng)景不會(huì)產(chǎn)生死鎖。不過,我們?cè)趯?shí)際應(yīng)用中可能無法完全按照相同順序修改數(shù)據(jù)。如果出現(xiàn)了不可避免的死鎖情況,另一種解決方法就是捕獲系統(tǒng)返回的死鎖異常并在程序中加入重試機(jī)制。
總結(jié)
本文簡要介紹了數(shù)據(jù)庫死鎖產(chǎn)生的原因和解決方法。到此這篇關(guān)于5分鐘快速了解數(shù)據(jù)庫死鎖產(chǎn)生的場(chǎng)景和解決方法的文章就介紹到這了,更多相關(guān)數(shù)據(jù)庫死鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- mysql 數(shù)據(jù)庫死鎖原因及解決辦法
- Mysql 數(shù)據(jù)庫死鎖過程分析(select for update)
- 簡單說明Oracle數(shù)據(jù)庫中對(duì)死鎖的查詢及解決方法
- InnoDB數(shù)據(jù)庫死鎖問題處理
- Mybatis update數(shù)據(jù)庫死鎖之獲取數(shù)據(jù)庫連接池等待
- MySQL數(shù)據(jù)庫的一次死鎖實(shí)例分析
- 講解Oracle數(shù)據(jù)庫中結(jié)束死鎖進(jìn)程的一般方法
- 記一次公司倉庫數(shù)據(jù)庫服務(wù)器死鎖過程及解決辦法
- 查詢Sqlserver數(shù)據(jù)庫死鎖的一個(gè)存儲(chǔ)過程分享
- MySQL數(shù)據(jù)庫之Purge死鎖問題解析
相關(guān)文章
詳解Flink同步Kafka數(shù)據(jù)到ClickHouse分布式表
這篇文章主要為大家介紹了Flink同步Kafka數(shù)據(jù)到ClickHouse分布式表實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12sql中l(wèi)eft join的效率分析與提高效率方法
網(wǎng)站隨著數(shù)據(jù)量與訪問量越來越大,訪問的速度變的越來越慢,于是開始想辦法解決優(yōu)化速度慢的原因,下面是對(duì)程序中一條sql的分析與提高效率的過程2018-03-03聊聊Navicat統(tǒng)計(jì)的行數(shù)竟然和表實(shí)際行數(shù)不一致的問題
Navicat作為數(shù)據(jù)庫管理工具,在業(yè)界廣受歡迎,這篇文章主要介紹了Navicat統(tǒng)計(jì)的行數(shù)竟然和表實(shí)際行數(shù)不一致的問題,需要的朋友可以參考下2021-12-12Apache?Doris?Colocate?Join?原理實(shí)踐教程
這篇文章主要為大家介紹了Apache?Doris?Colocate?Join?原理實(shí)踐教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10Nebula?Graph解決風(fēng)控業(yè)務(wù)實(shí)踐
本文主要講述?Nebula?Graph?是如何通過眾安保險(xiǎn)的選型,以及?Nebula?Graph?又是如何落地到具體業(yè)務(wù)場(chǎng)景幫助眾安保險(xiǎn)解決風(fēng)控問題,有需要的朋友可以借鑒參考下2022-03-03ubuntu中使用docker下載華為opengauss數(shù)據(jù)庫超簡單步驟
openGauss是關(guān)系型數(shù)據(jù)庫,采用客戶端/服務(wù)器,單進(jìn)程多線程架構(gòu),支持單機(jī)和一主多備部署方式,備機(jī)可讀,支持雙機(jī)高可用和讀擴(kuò)展,這篇文章主要給大家介紹了關(guān)于ubuntu中使用docker下載華為opengauss數(shù)據(jù)庫超的簡單步驟,需要的朋友可以參考下2024-04-04