您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關MySQL 數據庫中update語句會不會發生死鎖,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
最近生產上的 MySQL 數據庫,是不是的就來一次 DeadLock,其中我做了故障排查,昨天做了相關的升級,導致昨天非常的忙,很多網友加我好友,都沒有及時回應,直到晚上升級結束,我在群里做了相關的解釋!
截了一段錯誤日志信息如下:
其中涉及到的更新語句如下:
很奇妙吧,執行一條 update sql 竟然會有死鎖?
具體死鎖的提前是 i_pay_record 表中的 order_id 字段有索引。
下面我們通過新建一張表 xttblog,來說明問題。
當我們執行下面的 update 語句時,就有可能發生死鎖!
mysql 的事務支持與存儲引擎有關,MyISAM 不支持事務,INNODB 支持事務,更新時可能采用的是行級鎖,也可能是表級鎖。我們這里采用的是 INNODB 做存儲引擎,意味著會將 update 語句做為一個事務來處理。前面的文章中我提到了行級鎖必須建立在索引的基礎上,上面的更新語句用到了索引 idx_1,所以這里肯定會加上行級鎖。
行級鎖并不是直接鎖記錄,而是鎖索引(前面的文章也解釋過)。
如果一條 SQL 語句用到了主鍵索引,mysql 會鎖住主鍵索引;如果一條語句操作了非主鍵索引,mysql 會先鎖住非主鍵索引,再鎖定主鍵索引。
這個 update 語句會執行以下步驟:
由于用到了非主鍵索引,首先需要獲取 idx_1 上的行級鎖
緊接著根據主鍵進行更新,所以需要獲取主鍵上的行級鎖
更新完畢后,提交,并釋放所有鎖
如果在步驟 1 和 2 之間突然插入一條語句:update xttblog …..where id=? and user_id=? 這條語句,那么會先鎖住主鍵索引,然后鎖住 idx_1。
這時,悲劇就發生了!
一條語句獲取了 idx_1 上的鎖,等待主鍵索引上的鎖;另一條語句獲取了主鍵上的鎖,等待 idx_1 上的鎖,這樣就出現了死鎖。
很驚奇吧,其實一點也不奇怪,只要你了解了 MySQL 的一些底層設計原理!
那么發生這種問題,有解決方案嗎?
當然有了,要不然我寫這篇文章干什么?
解決方案,最笨最靠譜的做法就是:先獲取需要更新的記錄的主鍵,然后再逐條更新!
這樣就可以解決問題了,但是這個解決方案與先前的更新語句不一樣,先前的更新語句對所有記錄的更新在一個事務中,采用循環更新后并不在同一個事務中,所以在 for 循環外面還得開一個事務。
在采用 INNODB 的 MySQL 中,更新操作默認會加行級鎖,行級鎖是基于索引的,在分析死鎖之前需要查詢一下 mysql 的執行計劃,看看是否用到了索引,用到了哪個索引,對于沒有用索引的操作會采用表級鎖。如果操作用到了主鍵索引會先在主鍵索引上加鎖,然后在其他索引上加鎖,否則加鎖順序相反。在并發度高的應用中,批量更新一定要帶上記錄的主鍵,優先獲取主鍵上的鎖,這樣可以減少死鎖的發生。
不是說 update 不會發生死鎖,而是你的程序沒遇到高并發而已!
關于MySQL 數據庫中update語句會不會發生死鎖就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。