【MySQL】死鎖案例之六
一 前言
死鎖,其實是一個很有意思也很有挑戰的技術問題,大概每個DBA和部分開發同學都會在工作過程中遇見 。關於死鎖我會持續寫一個系列的案例分析,希望能夠對想了解死鎖的朋友有所幫助。
二 案例分析
2.1 環境說明
MySQL 5.6.24 事務隔離級別為RR
create table tx ( id int not null primary key auto_increment , c1 int not null default 0, c2 int not null default 0, key idx_c1(c1) ) engine=innodb ; insert into tx values(24,3,4),(25,3,4), (26,3,4),(30,5,8);
2.2 測試用例
|
sess1 |
sess2 |
|
begin; |
begin |
T1 |
|
select * from tx where id=30 for update;
|
T2 |
update tx set c2=8 where c1=5; ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction |
|
T3 |
|
delete from tx where id=30; |
2.3 死鎖日誌
---------------------------------- LATEST DETECTED DEADLOCK ------------------------ 2018-03-27 15:40:40 0x7f75cafce700 *** (1) TRANSACTION: TRANSACTION 1850, ACTIVE 20 sec starting index read mysql tables in use 1, locked 1 LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s) MySQL thread id 379040, OS thread handle 140143994337024, query id 1521958 localhost root updating update tx set c2=8 where c1=5 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 27 page no 3 n bits 72 index PRIMARY of table `test`.`tx` trx id 1850 lock_mode X locks rec but not gap waiting *** (2) TRANSACTION: TRANSACTION 1849, ACTIVE 32 sec updating or deleting, thread declared inside InnoDB 4999 mysql tables in use 1, locked 1 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 379016, OS thread handle 140143893473024, query id 1521976 localhost root updating delete from tx where id=30 *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 27 page no 3 n bits 72 index PRIMARY of table `test`.`tx` trx id 1849 lock_mode X locks rec but not gap *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 27 page no 5 n bits 72 index idx_c1 of table `test`.`tx` trx id 1849 lock_mode X locks rec but not gap waiting *** WE ROLL BACK TRANSACTION (1)
2.4 分析死鎖日誌
首先要理解的是 對同一個欄位申請加鎖是需要排隊的。
其次表ty中索引idx_c1為非唯一普通索引,我們根據事務執行的時間順序來解釋,這樣比較好理解。
T1: sess2 執行select for update 操作持有記錄id=30的主鍵行鎖:PRIMARY of table test.tx lock_mode X locks rec but not gap
T2: sess1 語句update透過普通索引idx_c1更新c2,先獲取idx_c1 c1=5的X鎖lock_mode X locks rec but not gap,然後去申請對應主鍵id=30的行鎖,但是sess2 已經持有主鍵的行鎖,於是sess1 等待。
T3: sess2 執行根據主鍵id=30刪除記錄,需要申請id=30的行鎖以及c1=5的索引行鎖。但是sess1 以及持有該鎖,故會出現index idx_c1 of table test.tx trx id 1849 lock_mode X locks rec but not gap waiting
sess2(delete)等待sess1(update),sess1(update)等待sess2(select for update) 迴圈等待,造成死鎖。
對於RDBMS系統出現死鎖的根本原因都可以概括為:不同的事務加鎖的順序不一樣導致迴圈等待,進而導致死鎖。
2.5 解決方法
修改sess1 的update 為根據主鍵來更新 也即 update tx set c2=x where id=30,把加鎖方式改為順序加鎖,申請主鍵id的鎖,避免透過交叉加鎖,相互申請對方持有的鎖。
三 小結
上面的案例中出現死鎖是由於不同會話對普通索引idx_c1和主鍵相互競爭導致迴圈等待而出現死鎖的。生產過程中遇到高併發更新同一行的的時候可以考慮避免透過不同的索引進行更新,進而避免死鎖。
推薦閱讀
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22664653/viewspace-2152274/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【MySQL】死鎖案例之七MySql
- 【MySQL】死鎖案例之八MySql
- MySQL:Innodb 一個死鎖案例MySql
- MySQL批量更新死鎖案例分析MySql
- 故障分析 | MySQL死鎖案例分析MySql
- MySQL死鎖案例一(回滾導致死鎖)MySql
- MySQL死鎖案例二(自增列導致死鎖)MySql
- 剖析6個MySQL死鎖案例的原因以及死鎖預防策略MySql
- 死鎖案例二
- 死鎖案例三
- 死鎖案例分析
- MySQL死鎖案例 – Learn. Write. Repeat.MySql
- MySQL死鎖案例分析一(先delete,再insert,導致死鎖)MySqldelete
- GreatSQL 死鎖案例分析SQL
- MySQL 死鎖和鎖等待MySql
- 面試:什麼是死鎖,如何避免或解決死鎖;MySQL中的死鎖現象,MySQL死鎖如何解決面試MySql
- MySQL 死鎖解決MySql
- MySQL解決死鎖MySql
- MySQL死鎖問題MySql
- MySQL死鎖系列-線上死鎖問題排查思路MySql
- mysql行鎖和死鎖檢測MySql
- Mysql 兩階段鎖和死鎖MySql
- mysql死鎖最佳化MySql
- MySQL:死鎖一例MySql
- MySQL 死鎖問題分析MySql
- Mysql如何處理死鎖MySql
- MySQL列印死鎖日誌MySql
- MySQL:MTS和mysqldump死鎖MySql
- MySQL:一個死鎖分析 (未分析出來的死鎖)MySql
- MySQL鎖等待與死鎖問題分析MySql
- MySQL insert on duplicate key update 死鎖MySql
- MySQL強人“鎖”難《死磕MySQL系列 三》MySql
- MySQL死鎖系列-常見加鎖場景分析MySql
- MySQL:RR分析死鎖一列MySql
- MySQL死鎖分析與解決之路MySql
- mysql慢查詢,死鎖解決方案MySql
- MySQL:RR模式下死鎖一列MySql模式
- 記一次線上mysql死鎖MySql