如何判断数据库死锁和数据库死锁的处理方式

可参考: 数据库中死锁那些事儿 https://blog.csdn.net/eseaqyq/article/details/7795023
MySQL InnoDB死锁及死锁检测(四)http://www.ywnds.com/?p=4949

二、MySQL InnoDB死锁检测
1) 尽量不出现死锁

在代码层调整SQL操作顺序,或者缩短事务长度,以避免出现死锁。

2) 碰撞检测

当死锁出现时,Innodb会主动探知到死锁,并回滚了某一苦苦等待的事务。问题来了,Innodb是怎么探知死锁的?

核心就是数据库会把事务单元锁维持的锁和它所等待的锁都记录下来,Innodb提供了wait-for graph算法来主动进行死锁检测,每当加锁请求无法立即满足需要进入等待时,wait-for graph算法都会被触发。当数据库检测到两个事务不同方向地给同一个资源加锁(产生循序),它就认为发生了死锁,触发wait-for graph算法。比如,事务1给A加锁,事务2给B加锁,同时事务1给B加锁(等待),事务2给A加锁就发生了死锁。那么死锁解决办法就是终止一边事务的执行即可,这种效率一般来说是最高的,也是主流数据库采用的办法。

Innodb目前处理死锁的方法就是将持有最少行级排他锁的事务进行回滚。这也是相对比较简单的死锁回滚方式。死锁发生以后,只有部分或者完全回滚其中一个事务,才能打破死锁。对于事务型的系统,这是无法避免的,所以应用程序在设计必须考虑如何处理死锁。大多数情况下只需要重新执行因死锁回滚的事务即可。

wait-for graph原理

我们怎么知道图中四辆车是死锁的?

MySQL InnoDB死锁及死锁检测(四)

他们相互等待对方的资源,而且形成环路!我们将每辆车看为一个节点,当节点1需要等待节点2的资源时,就生成一条有向边指向节点2,最后形成一个有向图。我们只要检测这个有向图是否出现环路即可,出现环路就是死锁!这就是wait-for graph算法。

MySQL InnoDB死锁及死锁检测(四)

Innodb将各个事务看为一个个节点,资源就是各个事务占用的锁,当事务1需要等待事务2的锁时,就生成一条有向边从1指向2,最后行成一个有向图。

3)等锁超时

死锁超时也是一种常见的做法,就是等待锁持有时间,如果说一个事务持有锁超过设置时间的话,就直接抛出一个错误,参数innodb_lock_wait_timeout用来设置超时时间。如果有些用户使用哪种超长的事务,你就需要把锁超时时间大于事务执行时间。在这种情况下这种死锁超时的方式就会导致每一个死锁超时被发现的时间是无法接受的。

不要太担心死锁,你可能会在MySQL error log中看到关于死锁的警告信息,或者在show engine InnoDB status输出中看到它。尽管看起来是一个可怕的名字,但deadlock不是一个严重的问题,对于InnoDB来说,通常不需要做任何纠正操作。当两个事务开始修改多个表时,如果访问表的顺序不同,会出现互相等待对方释放锁,然后才能继续处理的情况。MySQL会立刻发现这种情况并且终止较小的事务,允许其他的事务执行。

你的应用程序的确需要错误处理逻辑来重启该事务。当你重新执行相同的SQL语句时,原来的时间问题不再适用:要么其他的事务已经执行完成,这样你就可以执行事务了,要么其他的事务还在处理过程中,你的事务只能等它结束。

如果不断警告发生死锁,你可能要review你的应用程序源代码,调整SQL操作顺序,或者缩短事务长度。你可以启用innodb_print_all_deadlocks选项,把deadlock信息记录到MySQL的错误日志总,而不是仅仅通过show engine innob status查看。

锁跟索引的关系

这时我们要注意到,money表虽然没有添加索引,但是InnoDB存储引擎会使用隐式的主键来进行锁定。对于没有索引或主键的表来说,那么MySQL会给整张表的所有数据行的加行锁。这里听起来有点不可思议,但是当sql运行的过程中,MySQL并不知道哪些数据行是id=1(没有索引嘛),如果一个条件无法通过索引快速过滤,存储引擎层面就会将所有记录加锁后返回,再由MySQL Server层进行过滤。但在实际使用过程当中,MySQL做了一些改进,在MySQL Server过滤条件,发现不满足后,会调用unlock_row方法,把不满足条件的记录释放锁 (违背了二段锁协议的约束)。这样做,保证了最后只会持有满足条件记录上的锁,但是每条记录的加锁操作还是不能省略的。可见即使是MySQL,为了效率也是会违反规范的。这种情况同样适用于MySQL的默认隔离级别RC。所以对一个数据量很大的表做批量修改的时候,如果无法使用相应的索引,MySQL过滤数据的的时候特别慢,就会出现虽然没有修改某些行的数据,但是它们还是被锁住了的现象。

猜你喜欢

转载自blog.csdn.net/ZHWang102107/article/details/83213874