本文介紹了MySQL死鎖錯誤的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
我的Web應用程序最多每秒運行以下查詢1-2次,具體取決于用戶流量:
UPDATE `click_rollups`
SET `clicks` = `clicks` + 1, `last_updated` = ?
WHERE `camp_id` = ?
AND `country` = ?
AND `clicks` < ?
AND `time_created` = ?
我們的日志顯示有時會出現此錯誤:
SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction
但是,click_rollups
僅在該事務的寫上下文中使用一次,因此我無法想象死鎖會以何種方式發生。僅使用SELECT
s在應用程序的其他位置查詢一次。
因此,這是否意味著這兩個獨立事務(UPDATE和SELECT-ONLY)的死鎖導致了問題,因為每個獨立事務只使用該表一次(并且使用該表的查詢不引用任何其他表)?或者是否存在行級鎖定問題,這可能意味著其中一個事務可能會與同一事務的其他事件發生死鎖?
InnoDB
進一步閱讀后,我發現,由于推薦答案確實使用行級鎖定,因此在僅插入或更新單行時可能會發生死鎖,因為操作不是原子的。我跑了:
SHOW ENGINE INNODB STATUS
以查找有關上次死鎖的信息。我發現:
------------------------
LATEST DETECTED DEADLOCK
------------------------
140106 17:22:41
*** (1) TRANSACTION:
TRANSACTION 63EB5222A, ACTIVE 0 sec starting index read
mysql tables in use 3, locked 3
LOCK WAIT 9 lock struct(s), heap size 3112, 6 row lock(s), undo log entries 2
MySQL thread id 4304350, OS thread handle 0x7fd3b74d3700, query id 173460207 192.168.0.2 sharecash Updating
UPDATE `click_rollups` SET `clicks` = `clicks` + 1, `last_updated` = '1389046961' WHERE `camp_id` = '27739' AND `country` = 'US' AND `clicks` < '1000' AND `time_created` = '1389046866'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 186 page no 407 n bits 1272 index `country` of table `sharecash`.`click_rollups` trx id 63EB5222A lock_mode X waiting
*** (2) TRANSACTION:
TRANSACTION 63EB52225, ACTIVE 0 sec fetching rows
mysql tables in use 3, locked 3
177 lock struct(s), heap size 31160, 17786 row lock(s), undo log entries 2
MySQL thread id 4304349, OS thread handle 0x7fd6961c8700, query id 173460194 192.168.0.1 sharecash Updating
UPDATE `click_rollups` SET `clicks` = `clicks` + 1, `last_updated` = '1389046961' WHERE `camp_id` = '30949' AND `country` = 'US' AND `clicks` < '1000' AND `time_created` = '1388964767'
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 186 page no 407 n bits 1272 index `country` of table `sharecash`.`click_rollups` trx id 63EB52225 lock_mode X
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 186 page no 512 n bits 384 index `PRIMARY` of table `sharecash`.`click_rollups` trx id 63EB52225 lock_mode X locks rec but not gap waiting
*** WE ROLL BACK TRANSACTION (1)
您可以看到,導致死鎖的兩個查詢實際上是完全相同的。它顯示WHERE子句中的列也有不同的參數,因此被鎖定的實際行是不同的,這似乎有點違反我的直覺-對不同行集的操作如何會導致死鎖?
答案似乎是死鎖是由查詢引擎鎖定索引結構中的條目引起的。如果您查看上面的輸出,您可以看到一個事務鎖定了country
索引中某個頁面的特定部分,并且需要鎖定主鍵索引的一部分,而另一個事務基本上是相反的情況。
在我們的應用程序的這一部分中有一個不變量,只有一行的點擊次數會少于1000次,所以我相信通過解決這個問題,死鎖問題將被最小化,因為總體上會減少鎖定。MySQL文檔建議對應用程序進行編碼,以便在由于死鎖而導致回滾的情況下始終重新發布事務,這將防止導致頁面錯誤的問題。然而,如果任何人有任何關于如何實際避免這些死鎖的其他想法,請再次在評論中發布它們!
編輯-
country
索引不需要由事務使用,因為對于每個camp_id
值,只有幾個(通常只有1個)不同的country
值,每個值只對應于一行。我已經向查詢添加了一個索引提示,使其停止使用該索引,該問題現在已得到修復,而不會對性能造成任何影響(可能會有一些小的提高)。
這篇關于MySQL死鎖錯誤的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,