【MySQL】死锁案例之六


死锁,其实是一个很有意思也很有挑战的技术问题,大概每个DBA和部分开发同学都会在工作过程中遇见 。关于死锁我会持续写一个系列的案例分析,希望能够对想了解死锁的朋友有所帮助。

MySQL 5.6.24 事务隔离级别为RR

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;

首先要理解的是 对同一个字段申请加锁是需要排队的。

其次表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系统出现死锁的根本原因都可以概括为:不同的事务加锁的顺序不一样导致循环等待,进而导致死锁。

修改sess1 的update 为根据主键来更新 也即update tx set c开发云主机域名2=x where id=30,把加锁方式改为顺序加锁,申请主键id的锁,避免通过交叉加锁,相互申请对方持有的锁。

上面的案例中出现死锁是由于不同会话对普通索引idx_c1和主键相互竞争导致循环等待而出现死锁的。生产过程中遇到高并发更新同一行的的时候可以考虑避免通过不同的索引进行更新,进而避免死锁。

推荐阅读

如何阅读死锁日志

漫谈死锁

死锁案例之一

死锁案例之二

死锁案例之三

死锁案例之四

死锁案例之五

相关推荐: mysql学习8:第四章:数据库文件–日志文件

默认存放路径在数据目录下,以error.log结尾的文件。 查看文件位置: show variables like ‘%og_error%’; 注意warnings信息 TIMESTAMP类型特点 记录提交后的所有DML语句。如需记录select 和show,…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 06/04 21:59
下一篇 06/04 21:59

相关推荐