MySQL如何处理死锁?代码举例讲解

MySQL中死锁发生时,InnoDB存储引擎的默认行为是将一个事务回滚,从而解除死锁。
死锁示例:

sql
# 线程1
START TRANSACTION;
UPDATE table1 SET col = 1 WHERE id = 1; 
# 等待线程2释放锁

# 线程2 
START TRANSACTION;
UPDATE table1 SET col = 1 WHERE id = 2;
# 等待线程1释放锁  

# 死锁产生,线程1等待线程2,线程2等待线程1

InnoDB存储引擎检测到死锁后,会选择一个事务进行回滚,例如线程1的事务,然后线程2的事务就可以继续执行。
线程1会收到类似如下错误:

Deadlock found when trying to get lock; try restarting transaction

提示发现死锁,事务被回滚。

MySQL死锁的四个必要条件:

  1. 互斥:一个资源每次只能被一个事务使用。
  2. 请求并持有:一个事务已经持有一个资源,并且又请求新资源。
  3. 不可剥夺:在事务没有主动释放的情况下,持有的资源不能被其他事务强制夺走。
  4. 循环等待:两个或者多个事务之间形成一条等待链。

避免死锁的措施:

  1. 保证所有事务按同一顺序请求锁。
  2. 避免一个事务请求其他事务持有的锁。
  3. 锁的持有时间越短越好。
  4. 尽量避免更新多个表的语句,可以拆分成多个语句分别更新。

如果无法避免,就需要设置合理的死锁检测和解决策略。在MySQL中可以调整innodb_lock_wait_timeout参数控制死锁检测时间。