mysql innodb的死锁问题

一、先了解下innodb锁机制,实现原理:

InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁! 索引分为主键索引和二级索引两种,如果一条sql语句操作了主键索引,MySQL就会锁定这条主键索引;如果一条语句操作了二级索引,MySQL会先锁定该二级索引,再锁定相关的主键索引。

然后innodb行锁分为以下情形:

1)Record lock :对索引项加锁,即锁定一条记录。
2)Gap lock:对索引项之间的‘间隙’、对第一条记录前的间隙或最后一条记录后的间隙加锁,即锁定一个范围的记录,不包含记录本身
3)Next-key Lock:锁定一个范围的记录并包含记录本身(上面两者的结合)。
4)insert intention lock(IK)
如果插入前,该间隙已经由gap锁,那么Insert会申请插入意向锁。因为了避免幻读,当其他事务持有该间隙的间隔锁,插入意向锁就会被阻塞。

注意:InnoDB默认级别是repeatable-read级别,所以下面说的都是在RR级别中的。

Next-Key Lock是行锁与间隙锁的组合,这样,当InnoDB扫描索引记录的时候,会首先对选中的索引记录加上行锁(Record Lock),再对索引记录两边的间隙加上间隙锁(Gap Lock)。如果一个间隙被事务T1加了锁,其它事务是不能在这个间隙插入记录的

行锁防止别的事务修改或删除,GAP锁防止别的事务新增(防止新增包括insert和update已有数据到这个范围中),行锁和GAP锁结合形成的的Next-Key锁共同解决了RR级别在写数据时的部分幻读问题,一定注意只是部分幻读问题;

当当前索引是一个普通索引(即不一定唯一)的时候,会加一个gap lock来防止幻读,此gap lock 会锁住一个左开右闭的区间。假设索引为xx_idx(xx_id),数据分布为1,4,6,8,12,当更新xx_id=9的时候,这个时候gap lock的锁定记录区间就是(8,12],也就是锁住了xxid in (9,10,11,12)的数据,当有其他事务要插入xxid in (9,10,11,12)的数据时,就会处于等待获取锁的状态。

主键和唯一索引可以锁定一行,所以不需要间隙锁锁定。
如果列没有索引或者具有非唯一索引,该语句会锁定当前索引前的间隙。

二、举个死锁例子

mysql innodb的死锁问题_第1张图片

事务A正在获取插入意向锁,持有排他gap锁
事务B正在获取插入意向锁

那么就可以推断出:事务A持有gap lock,等待事务B的insert intention lock释放;事务B持有gap lock,等待事务A的insert intention lock释放,从而导致死锁。

https://www.cnblogs.com/twoheads/p/10703023.html

你可能感兴趣的:(数据库)