MySQL死锁的原因及解决方法
这篇文章主要介绍“MySQL死锁的原因及解决方法”,在日常操作中,相信很多人在MySQL死锁的原因及解决方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”MySQL死锁的原因及解决方法”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
一、问题由来这是我同事问我的一个问题,在网上看到了如下案例,本案例RC RR都可以出现,其实这个死锁原因也不叫简单,我们来具体看看:
构造数据CREATEdatabasedeadlock_test;usedeadlock_test;CREATETABLE`push_token`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`token`varchar(128)NOTNULLCOMMENT'pushtoken',`app_id`varchar(128)DEFAULTNULLCOMMENT'appid',`deleted`tinyint(1)NOTNULLCOMMENT'是否已删除0:否1:是',PRIMARYKEY(`id`),UNIQUEKEY`uk_token_appid`(`token`,`app_id`))ENGINE=InnoDBAUTO_INCREMENT=3384DEFAULTCHARSET=utf8COMMENT='pushtoken表';insertintopush_token(id,token,app_id,deleted)values(1,"token1",1,0);操作数据s1(TRX_ID367661) s2(TRX_ID367662) s3(TRX_ID367663) begin; UPDATE push_token SET deleted = 1 WHERE token = ‘token1’ AND app_id = ‘1’;
begin; DELETE FROM push_token WHERE id IN (1);
begin; UPDATE push_token SET deleted = 1 WHERE token = ‘token1’ AND app_id = ‘1’;commit;
Query OK, 0 rows affected (0.00 sec)Query OK, 1 row affected (17.32 sec)ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction二、分析方法
我使用的分析方法是把整个加锁的日志打印出来,当然需要用到我自己做了输出修改的一个版本,如下:
https://github.com/gaopengcarl/percona-server-locks-detail-5.7.22
这个版本我打开了的日志记录参数如下:
mysql>showvariableslike'%gaopeng%';+--------------------------------+-------+|Variable_name|Value|+--------------------------------+-------+|gaopeng_mdl_detail|OFF||innodb_gaopeng_row_lock_detail|ON|+--------------------------------+-------+2rowsinset(0.01sec)
这样大部分的innodb加锁记录都会记录到errlog日志了。好了下面我详细分析一下日志:
三、分析过程初始化的情况整个表只有1条记录,本表包含一个主键和一个唯一键。
s1(TRX_ID367661) 执行语句begin;UPDATEpush_tokenSETdeleted=1WHEREtoken='token1'ANDapp_id='1';
日志输出:
2019-08-18T19:10:05.117317+08:006[Note]InnoDB:TRXID:(367661)table:deadlock_test/push_tokenindex:uk_token_appidspace_id:449page_id:4heap_no:2rowlockmode:LOCK_X|LOCK_NOT_GAP|PHYSICALRECORD:n_fields3;compactformat;infobits00:len6;hex746f6b656e31;asctoken1;;1:len1;hex31;asc1;;2:len8;hex8000000000000001;asc;;2019-08-18T19:10:05.117714+08:006[Note]InnoDB:TRXID:(367661)table:deadlock_test/push_tokenindex:PRIMARYspace_id:449page_id:3heap_no:2rowlockmode:LOCK_X|LOCK_NOT_GAP|PHYSICALRECORD:n_fields6;compactformat;infobits00:len8;hex8000000000000001;asc;;1:len6;hex000000059c2c;asc,;;2:len7;hexbf000000420110;ascB;;3:len6;hex746f6b656e31;asctoken1;;4:len1;hex31;asc1;;5:len1;hex80;asc;;
我们看到主键和唯一键都加锁了如下图:
s2(TRX_ID367662) 执行语句begin;DELETEFROMpush_tokenWHEREidIN(1);`
日志输出:
2019-08-18T19:10:22.751467+08:009[Note]InnoDB:TRXID:(367662)table:deadlock_test/push_tokenindex:PRIMARYspace_id:449page_id:3heap_no:2rowlockmode:LOCK_X|LOCK_NOT_GAP|PHYSICALRECORD:n_fields6;compactformat;infobits00:len8;hex8000000000000001;asc;;1:len6;hex000000059c2d;asc-;;2:len7;hex400000002a1dc8;asc@*;;3:len6;hex746f6b656e31;asctoken1;;4:len1;hex31;asc1;;5:len1;hex81;asc;;2019-08-18T19:10:22.752753+08:009[Note]InnoDB:Trx(367662)isblocked!!!!!
这个时候S2需要获取主键上的锁,因此被堵塞了如下图:
s3(TRX_ID367663) 执行语句begin;UPDATEpush_tokenSETdeleted=1WHEREtoken='token1'ANDapp_id='1';`
日志输出:
019-08-18T19:10:30.822111+08:008[Note]InnoDB:TRXID:(367663)table:deadlock_test/push_tokenindex:uk_token_appidspace_id:449page_id:4heap_no:2rowlockmode:LOCK_X|LOCK_NOT_GAP|PHYSICALRECORD:n_fields3;compactformat;infobits00:len6;hex746f6b656e31;asctoken1;;1:len1;hex31;asc1;;2:len8;hex8000000000000001;asc;;2019-08-18T19:10:30.918248+08:008[Note]InnoDB:Trx(367663)isblocked!!!!!
这个时候S3需要获取唯一键上的锁,因此被堵塞了如下图:
s1(TRX_ID367661) 执行语句这一步完成后死锁出现。
commit;
日志输出如下:
367663和367662各自获取需要的锁2019-08-18T19:10:36.566733+08:008[Note]InnoDB:TRXID:(367663)table:deadlock_test/push_tokenindex:uk_token_appidspace_id:449page_id:4heap_no:2rowlockmode:LOCK_X|LOCK_NOT_GAP|PHYSICALRECORD:n_fields3;compactformat;infobits00:len6;hex746f6b656e31;asctoken1;;1:len1;hex31;asc1;;2:len8;hex8000000000000001;asc;;2019-08-18T19:10:36.568711+08:009[Note]InnoDB:TRXID:(367662)table:deadlock_test/push_tokenindex:PRIMARYspace_id:449page_id:3heap_no:2rowlockmode:LOCK_X|LOCK_NOT_GAP|PHYSICALRECORD:n_fields6;compactformat;infobits00:len8;hex8000000000000001;asc;;1:len6;hex000000059c2d;asc-;;2:len7;hex400000002a1dc8;asc@*;;3:len6;hex746f6b656e31;asctoken1;;4:len1;hex31;asc1;;5:len1;hex81;asc;;367663获取主键锁堵塞、367662获取唯一键锁堵塞,死锁形成2019-08-18T19:10:36.570313+08:008[Note]InnoDB:TRXID:(367663)table:deadlock_test/push_tokenindex:PRIMARYspace_id:449page_id:3heap_no:2rowlockmode:LOCK_X|LOCK_NOT_GAP|PHYSICALRECORD:n_fields6;compactformat;infobits00:len8;hex8000000000000001;asc;;1:len6;hex000000059c2d;asc-;;2:len7;hex400000002a1dc8;asc@*;;3:len6;hex746f6b656e31;asctoken1;;4:len1;hex31;asc1;;5:len1;hex81;asc;;2019-08-18T19:10:36.571199+08:008[Note]InnoDB:Trx(367663)isblocked!!!!!2019-08-18T19:10:36.572481+08:009[Note]InnoDB:TRXID:(367662)table:deadlock_test/push_tokenindex:uk_token_appidspace_id:449page_id:4heap_no:2rowlockmode:LOCK_X|LOCK_NOT_GAP|PHYSICALRECORD:n_fields3;compactformat;infobits00:len6;hex746f6b656e31;asctoken1;;1:len1;hex31;asc1;;2:len8;hex8000000000000001;asc;;2019-08-18T19:10:36.573073+08:009[Note]InnoDB:Transactionsdeadlockdetected,dumpingdetailedinformation.
这个时候我们看到s2和s3先是获取了各自需要的锁,s3获取主键锁堵塞,s2获取唯一键锁堵塞,死锁出现。如下图:
到此,关于“MySQL死锁的原因及解决方法”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。