熟悉或者了解数据库的朋友都知道锁的概念,这里不做过多的解析!锁的种类有很多,不同数据库的锁管理方式也不同。这里主要谈下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;
2begin;
3select * from test where
a = 4 for update;
4select * from test where
a<=4 lock in share mode;
#等待
5insert 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引擎在这里主动选择死锁。