MySQL 死锁的产生与处理
死锁产生的原因
所谓死锁,是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。表级锁不会产生死锁。所以解决死锁主要还是针对于最常用的InnoDB。
死锁的关键在于:两个(或以上)的 Session 加锁的顺序不一致。
那么对应的解决死锁问题的关键就是:让不同的 Session 加锁有次序。
死锁的现象
事务1和事务2分别对id为1,2的数据进行排它锁加锁,随后进行交叉的数据修改。
事务顺序 | 事务1 | 事务2 |
---|---|---|
① | begin; | begin; |
② | select * from user where id = 1 for update; | select * from user where id = 2 for update; |
③ | update user set username = “lisi” where id = 2; | update user set username = “zhangsan” where id = 1; |
④ | commit; | commit; |
运行结果:
尽可能的避免事务死锁
- 以固定的顺序访问表和行。比如对第二节两个job批量更新的情形,简单方法是对id列表现排序,后执行,这样避免了交叉等待锁的情形。
- 大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。
- 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率。
- 降低隔离级别。如果业务允许,将隔离级别调低也是较号的选择,比如将隔离级别从 RR 调整为 RC,可以避免掉很多因为 gap 锁造成的死锁。
- 为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添加上锁,死锁的概率大大增大。