如何预防数据库死锁?生产环境如何避免死锁?

死锁是指两个或两个以上的事务在执行过程中, 因争夺锁资源而造成的一种互相等待的现象 。若无外力作用, 事 务都将无法推进下去 。解决死锁问题最简单的方式是不要有等待, 将任何的等待都转化为回滚, 并且事务重新开 始 。 毫无疑问, 这的确可以避免死锁问题的产生 。 然而在线上环境中, 这可能导致并发性能的下降, 甚至任何一 个事务都不能进行 。 而这所带来的问题远比死锁问题更为严重, 因为这很难被发现并且浪费资源。

解决死锁问题最简单的一种方法是超时, 即当两个事务互相等待时, 当一个等待时间超过设置的某一 阈值时, 其 中一个事务进行回滚, 另一个等待的事务就能继续进行 。在InnoDB存储引擎中, 参数innodb_lock_wait_timeout用 来设置超时的时间。

超时机制虽然简单, 但是其仅通过超时后对事务进行回滚的方式来处理, 或者说其是根据FIFO的顺序选择回滚对 象 。但若超时的事务所占权重比较大, 如事务操作更新了很多行, 占用了较多的undo log, 这时采用FIFO的方式, 就显得不合适了, 因为回滚这个事务的时间相对另一个事务所占用的时间可能会很多。

因此, 除了超时机制, 当前数据库还都普遍采用wait-for graph (等待图) 的方式来进行死锁检测 。较之超时的解 决方案, 这是一种更为主动的死锁检测方式 。 InnoDB存储引擎也采用的这种方式 。wait-for graph要求数据库保存 以下两种信息:

锁的信息链表

事务等待链表

mysql如何避免or mysql 避免死锁_存储引擎

mysql如何避免or mysql 避免死锁_存储引擎_02

事务T1指向T2边的定义为:

❑事务T1等待事务T2所占用的资源

❑事务T1最终等待T2所占用的资源, 也就是事务之间在等待相同的资源, 而事务T1发生在事务T2的后面

通过等待图可以发现存在回路 (t1, t2) , 因此存在死锁 。 通过上述的介绍, 可以发现wait-for graph是一种 较为主动的死锁检测机制, 在每个事务请求锁并发生等待时都会判断是否存在回路, 若存在则有死锁, 通常 来说InnoDB存储引擎选择回滚undo量最小的事务。