熟悉或者了解数据库的朋友都知道锁的概念,这里不做过多的解析!锁的种类有很多,不同数据库的锁管理方式也不同。这里主要谈下MySQL innodb引擎下的死锁。


死锁通俗的来讲就是2个事务相互请求对方持有的锁,这样就会造成2个事务相互等待对方释放的锁资源,于是这就是死锁。

事务A事务B
begin;

select * from t where a = 1 for update;begin;

select * from t where a = 2 for update;

select * from t where a = 2 for update;
#等待



select * from t where a = 1 for update;

#ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

首先INNODB引擎不会回滚大多数的异常,但死锁除外。再发现死锁后,Innodb会立即回滚其中一个事务(这里回滚依据,会设计到权重问题)。例子中事务B被回滚!这是最常见的一种死锁例子。


MySQL还有另外一种死锁情况:当前事务持有待插入记录的下一个记录的X锁(排他锁),但此时等待的队列中存在一个S锁的请求,则可能会发生死锁。首先创建一个测试用的表,并插入数据:

create table test( a int primary key) engine=innodb;

insert into test values (1),(2),(4),(5);

时间事务A事务B
1begin;
2
begin;
3

select * from test where

 a = 4 for update;


4

select * from test where

a<=4 lock in share mode;

#等待

5

insert into test values (3)

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction


6
#事务获得锁,正常运行

事务A中已经对记录4持有了X锁,但会话A插入记录3的时候会导致死锁发生。这个问题产生是由于事务B中请求记录4的S锁而发生等待,但之前请求锁对于主键记录1、2都已经成功,若再时间5能插入记录,那么事务B在获取记录4持有的S锁后,还需要向后获得记录3的记录,这显得不合理。于是INNODB引擎在这里主动选择死锁。