下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922

全面分析Mysql死锁以及死锁日志

作者:课课家教育     来源: http://www.kokojia.com点击数:780发布时间: 2017-09-29 10:28:15

标签: 数据库基础数据库管理数据库开发数据库安全

  今天,我们来说一下MySQL死锁以及死锁日志,有需要的小伙伴,可以参考一下。课课家教育平台提醒各位:本篇文章纯干货~因此大家一定要认真阅读本篇文章哦!

     死锁的概念

  死锁:死锁一般是事务相互等待对方资源,最后形成环路造成的。

  对于死锁,数据库处理方法:牺牲一个连接,保证另外一个连接成功执行。

  发生死锁会返回ERROR:1213 错误提示,大部分的死锁InnoDB存储引擎本身可以侦测到,不需要人为进行干预。

  注意:

  InnoDB存储引擎并不会回滚大部分的错误异常,像阻塞章节里面的例子,但是死锁例外,发现死锁后,InnoDB存储引擎会马上回滚一个事务,会返回1213错误。

  死锁的情形举例

  eg1:

全面分析Mysql死锁以及死锁日志_数据库基础_数据库管理_数据库开发_数据库安全_课课家教育
死锁的情形举例
死锁的情形举例

 

  分析死锁日志:

  第一部分

  从日志里我们可以看到事务1当前正在执行update info_users set mobile='18514656666' where mobile='18514656620',该条语句正在申请表info_users的索引IDX_MOBILE的X锁,所以提示lock_mode X waiting

  第二部分:

  然后日志的下半部分说明了事务2当前‘持有的锁’以及‘等待的锁’:

  从日志的HOLDS THE LOCKS(S)块中我们可以看到事务2持有索引IDX_MOBILE的X锁,并且是记录锁(Record Lock)。该锁是通过事务2在步骤2执行的update语句申请的。

  从日志的WAITING FOR THIS LOCK TO BE GRANTED块中我们可以看到事务2正在申请持有表info_area的索引GEN_CLUST_INDEX的X锁,该锁是delete from info_area where id=1;语句申请的。

  eg2:

eg2:

  eg3:

  eg3:
  eg3:
  eg3:

  为了解决这个问题,数据库实现了各种死锁探查和超时机制。像InnoDB这样复杂的存储引擎会提示循环依赖并且立即返回错误。否则死锁将会导致查询非常缓慢。其他一些不好的做法是等待超时后放弃。当前InnoDB处理死锁的方式是回滚持有最少排他行级锁的事务。(几乎最简单的回滚的参考指标)

  锁的行为是顺序是存储引擎决定的。因此,一些存储引擎可能会在特定的操作顺序下发生死锁,其他的可能没有。死锁有两种:一些是因为实际数据冲突而无法避免,一些是因为存储引擎的工作方式产生。

  只有部分或者完全回滚其中的一个事务才可能打破死锁。死锁是事务系统中客观存在的事实,你的应该在设计上必须应该考虑处理死锁。一些业务系统可以从头重试事务。

  如何处理死锁

  死锁是事务型数据库典型的问题,但是除非它们频繁出现以至于你更本不能运行某个事务,它们一般是不危险的。正常地,你必须编写你的应用程序使得它们总是准备如果因为死锁而 回滚一个事务就重新发出一个事务。

  InnoDB使用自动行级锁定。即使在只插入或删除单个行的事务的情况下,你可以遇到死锁。这是因为这些操作不是真正的“极小的”,它们自动对插入或删除的行的(可能是数个)索引记录设置锁定。

  你可以用下列技术对付死锁减少它们发生的可能性:

  用Use SHOW INNODB STATUS来确定最后一个死锁的原因。这样可以帮助你调节应用程序来避免死锁。

  总是准备着重新发出事务,如果它因为死锁而失败了。死锁不危险,再试一次。

  经常提交你的事务。小事务更少地倾向于冲突。

  如果你正使用锁定读,(SELECT ... FOR UPDATE或 ... LOCK IN SHARE MODE),试着用更低的隔离级别,比如READ COMMITTED。

  以固定的顺序访问你的表和行。则事务形成良好定义的查询并且没有死锁。

  添加精心选定的索引到你的表。则你的查询需要扫描更少的索引记录并且因此设置更少的锁定。使用EXPLAIN SELECT来确定对于你的查询,mysql认为哪个索引是最适当的。

     分析死锁日志:

  第一部分

  从日志里我们可以看到事务1当前正在执行DELETE from users where uid='bbb';,该条语句正在申请索引UID的X锁,所以提示lock_mode X waiting

  第二部分:

  然后日志的下半部分说明了事务2当前‘持有的锁’以及‘等待的锁’:

  从日志的HOLDS THE LOCKS(S)块中我们可以看到事务2持有索引UID的X锁,并且是记录锁(Record Lock)。该锁是通过事务2在步骤2执行的delete语句申请的。

  从日志的WAITING FOR THIS LOCK TO BE GRANTED块中我们可以看到事务2正在申请持有索引UID的S锁,该锁是insert INTO users VALUES(2,'bbb');语句申请的。insert语句在普通情况下是会申请X锁,但是这里出现了S锁。这是因为uid字段是一个唯一索引,所以insert语句会在插入前进行一次duplicate key的检查,为了使这次检查成功,需要申请S锁防止其他事务对uid字段进行修改。

  那么为什么该S锁会失败呢?这是对同一个字段的锁的申请是需要排队的。S锁前面还有一个未申请成功的X锁,所以S锁必须等待,所以形成了循环等待,死锁出现了。

  通过阅读死锁日志,我们可以清楚地知道两个事务形成了怎样的循环等待,再加以分析,就可以逆向推断出循环等待的成因,也就是死锁形成的原因。

     小结:相信最后大家阅读完毕本篇文章,肯定学到了不少知识吧?其实大家私下还得多多自学,当然如果大家还想了解更多方面的详细内容的话呢,不妨关注课课家教育平台,在这里你肯定会有意想不到的收获的!

赞(21)
踩(0)
分享到:
华为认证网络工程师 HCIE直播课视频教程