死锁是指多个事务无法继续进行的情况,因为每个事务都持有另一个事务所需的锁。由于所有参与的事务都在等待同一资源变得可用,因此它们都没有释放它们持有的锁。
当事务锁定多个表中的行(通过诸如 UPDATE
或 SELECT ... FOR UPDATE
之类的语句)但顺序相反时,可能会发生死锁。当此类语句锁定索引记录和间隙的范围,并且每个事务由于时间问题而获取了一些锁但没有获取其他锁时,也会发生死锁。有关死锁示例,请参见 第 17.7.5.1 节,“InnoDB 死锁示例”。
为了降低死锁的可能性,请使用事务而不是 LOCK TABLES
语句;确保插入或更新数据的交易足够小,以至于不会长时间保持打开状态;当不同的交易更新多个表或大量行时,在每个交易中使用相同的操作顺序(例如 SELECT ... FOR UPDATE
);在 SELECT ... FOR UPDATE
和 UPDATE ... WHERE
语句中使用的列上创建索引。死锁的可能性不受隔离级别影响,因为隔离级别会改变读取操作的行为,而死锁是由于写入操作造成的。有关避免和恢复死锁条件的更多信息,请参见 第 17.7.5.3 节,“如何最小化和处理死锁”。
当启用死锁检测(默认情况下)并且发生死锁时,InnoDB
会检测到这种情况并回滚其中一个事务(受害者)。如果使用 innodb_deadlock_detect
变量禁用死锁检测,InnoDB
将依赖于 innodb_lock_wait_timeout
设置在发生死锁的情况下回滚事务。因此,即使您的应用程序逻辑正确,您仍然必须处理必须重试事务的情况。要查看 InnoDB
用户事务中的最后一次死锁,请使用 SHOW ENGINE INNODB STATUS
。如果频繁的死锁突出了事务结构或应用程序错误处理的问题,请启用 innodb_print_all_deadlocks
将有关所有死锁的信息打印到 mysqld 错误日志中。有关如何自动检测和处理死锁的更多信息,请参见 第 17.7.5.2 节,“死锁检测”。