MySQL死锁
# MySQL死锁
# 什么是死锁
死锁是并发系统中常见的问题,一般表现为A,B同时持有对方需要的资源并上锁,A,B都在等待对方释放锁以获取对方手里的资源,如此便产生了死锁。同样也会出现在数据库MySQL的并发读写请求场景中。当两个及以上的事务,双方都在等待对方释放已经持有的锁或因为加锁顺序不一致造成循环等待锁资源,就会出现“死锁”。
# 死锁产生的四个必要条件
互斥条件资源是独占的且排他使用,进程互斥使用资源,即任意时刻一个资源只能给一个进程使用,其他进程若申请一个资源,而该资源被另一进程占有时,则申请者等待直到资源被占有者释放。
不可剥夺条件进程所获得的资源在未使用完毕之前,不被其他进程强行剥夺,而只能由获得该资源的进程资源释放。
请求和保持条件进程每次申请它所需要的一部分资源,在申请新的资源的同时,继续占用已分配到的资源。
循环等待条件在发生死锁时必然存在一个进程等待队列{P1,P2,…,Pn},其中P1等待P2占有的资源,P2等待P3占有的资源,…,Pn等待P1占有的资源,形成一个进程等待环路,环路中每一个进程所占有的资源同时被另一个申请,也就是前一个进程占有后一个进程所申请地资源。
以上给出了导致死锁的四个必要条件,只要系统发生死锁则以上四个条件至少有一个成立。事实上循环等待的成立蕴含了前三个条件的成立,似乎没有必要列出然而考虑这些条件对死锁的预防是有利的,因为可以通过破坏四个条件中的任何一个来预防死锁的发生。
参考死锁的MySQL 出现死锁的几个要素为:
- 两个或者两个以上事务
- 每个事务都已经持有锁并且申请新的锁
- 锁资源同时只能被同一个事务持有或者不兼容
- 事务之间因为持有锁和申请锁导致彼此循环等待
举例来说 A 事务持有 X1 锁 ,申请 X2 锁,B事务持有 X2 锁,申请 X1 锁。A 和 B 事务持有锁并且申请对方持有的锁进入循环等待,就造成了死锁。
create table money(id int primary key,price int);
insert into money values(1,1000);
insert into money values(2,1000);
2
3
事务A | 事务B |
---|---|
begin; update money set price = 1500 where id =1 | |
begin; update money set price = 1500 where id =2 | |
update money set price = 1600 where id =2 | |
update money set price = 1600 where id =1 |
事务A与事务B分别对ID=1与ID=2的记录加了锁,现在事务A需要获取ID=2的记录的锁,事务B需要获取ID=1的记录的锁,双方都在等对方释放锁,于是造成的死锁。
# 死锁的解决与防范
首先要做的就是预防死锁