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死锁的四个必要条件:
- 互斥:一个资源每次只能被一个事务使用。
- 请求并持有:一个事务已经持有一个资源,并且又请求新资源。
- 不可剥夺:在事务没有主动释放的情况下,持有的资源不能被其他事务强制夺走。
- 循环等待:两个或者多个事务之间形成一条等待链。
避免死锁的措施:
- 保证所有事务按同一顺序请求锁。
- 避免一个事务请求其他事务持有的锁。
- 锁的持有时间越短越好。
- 尽量避免更新多个表的语句,可以拆分成多个语句分别更新。
如果无法避免,就需要设置合理的死锁检测和解决策略。在MySQL中可以调整innodb_lock_wait_timeout参数控制死锁检测时间。