事務一 | 事務二 | 備注 |
---|---|---|
BEGIN; | BEGIN; | 分別開始兩個事務 |
UPDATE t_lock SET col = col + 100 WHERE id = 1; |
UPDATE t_lock SET col = col + 200 WHERE id = 2; |
事務一修改 id=1 的數據,事務二修改 id=2 的數據 |
UPDATE t_lock SET col = col + 100 WHERE id = 2; |
事務一修改 id=2 的數據,需要等待事務二釋放寫鎖 | |
等待中… | UPDATE t_lock SET col = col + 200 WHERE id = 1; |
事務二修改 id=1 的數據,需要等待事務一釋放寫鎖 |
死鎖 | 死鎖 | 數據庫檢測到死鎖,選擇中止一個事務 |
更新成功 | 返回錯誤 |
對于 MySQL InnoDB,默認啟用了 innodb_deadlock_detect 選項,事務二返回以下錯誤信息:
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
如果我們禁用 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,狀態 51,第 7 行
事務(進程 ID 67)與另一個進程被死鎖在 鎖 資源上,并且已被選作死鎖犧牲品。請重新運行該事務。
PostgreSQL 檢測到死鎖時返回的錯誤如下:
SQL 錯誤 [40P01]: 錯誤: 檢測到死鎖
詳細:進程32等待在事務 4765上的ShareLock; 由進程16552阻塞.
進程16552等待在事務 4766上的ShareLock; 由進程32阻塞.
建議:詳細信息請查看服務器日志.
在位置:當更新關系"t_lock"的元組(0, 1)時
死鎖不是數據庫自身的問題,我們無法通過優化數據庫配置來解決或者避免死鎖,只能通過修改應用程序來解決。簡單來說,我們應該在程序中按照相同的順序修改數據,避免產生相互等待資源的情況發生。例如:
事務一 | 事務二 | 備注 |
---|---|---|
BEGIN; | BEGIN; | 分別開始兩個事務 |
UPDATE t_lock SET col = col + 100 WHERE id = 1; |
UPDATE t_lock SET col = col + 200 WHERE id = 1; |
事務一和事務二都修改 id=1 的數據,后執行的事務需要等待 |
UPDATE t_lock SET col = col + 100 WHERE id = 2; |
等待中… | 事務一修改 id=1 的數據,事務二等待中 |
COMMIT; | 等待中… | 事務一提交 |
UPDATE t_lock SET col = col + 200 WHERE id = 2; |
事務二繼續修改 id=2 的數據 | |
COMMIT; | 事務二提交 |
以上場景不會產生死鎖。不過,我們在實際應用中可能無法完全按照相同順序修改數據。如果出現了不可避免的死鎖情況,另一種解決方法就是捕獲系統返回的死鎖異常并在程序中加入重試機制。
本文簡要介紹了數據庫死鎖產生的原因和解決方法。到此這篇關于5分鐘快速了解數據庫死鎖產生的場景和解決方法的文章就介紹到這了,更多相關數據庫死鎖內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!