MySQL InnoDB中的行锁 Next-Key Lock消除幻读

InnoDB中有三种行锁技术:

  1. Record Lock:单个行记录上的锁,我们通常讲的行锁,它的实质是通过对索引的加锁实现只有通过索引条件检索数据InnoDB才使用行级锁,否则,InnoDB将使用表锁。在事务隔离级别为读已提交下,仅采用Record Lock。
  2. Gap Lock:间隙锁,锁定一个范围,但不包含记录本身;
  3. Next-Key Lock:Record Lock+Gap Lock,锁定一个范围,并且锁定记录本身

1. Next-Key Lock

Next-Key Lock是结合Record Lock与Gap Lock的一种锁定方法,它锁定了包括记录本身的一个范围。

id name
10 a
20 b
50 c

如果索引为 10,20,50,那么:
Record Lock:select * from tab where id = 10 for update; //对id=10单行进行加锁
Gap Lock锁范围:(- ,10)(10,20)(20,50)(50,+
Next-Key Lock锁范围:(- ,10)[10,20)[20,50)[50,+

事务A 事务B
set autocommit=0;
select * from tab where id>10 for update; //查询结果为20,50
select * from tab where id=10 for update;//执行等待,Next-Key Lock锁机制暴露
commit;
继续执行,查询结果为10
select * from tab where id=10 for update; //查询结果为10
select * from tab where id=10 for update; //等待执行
commit;
继续执行,查询结果为10
select * from tab where id=10 for update; //查询结果为10,锁降级为Record Lock
select * from tab where id>20 for update; //立即执行,查询结果为50

应该从上面的例子中看出了一些问题。

  1. Next-Key Lock的加锁方式
  2. 当查询的索引含有唯一属性时,InnoDB会对Next-Key Lock进行优化,将其降级为Record Lock,即仅锁住索引本身,而不是范围。上表中的第三个事例中可看出.

2. 为什么会存在Next-Key Lock

InnoDB能在可重复读的事务隔离级别下消除幻读
一般的数据库避免幻读需要在串行化的事务隔离级别下,而InnoDB在可重复读的事务隔离级别下消除幻读;这样能够有效提高数据库的并发度。

3. 幻读

幻读是指在同一事务下,连续执行两次同样的SQL语句可能导致不同的结果,第二次的SQL语句可能会返回之前不存在的行。

事务A 事务B
SET SESSION tx_isolation=’READ-COMMITTED’;
begin; select * from tab where id>10 for update; //查询结果为20,50
begin; insert into tab values(30,c); commit;
select * from tab where id>10 for update; //查询结果为20,30,50;出现幻读

4. Next-Key Lock避免幻读

关键点在于对查询范围进行加锁,在另一个事务执行插入操作时是不被运行的,从而避免了幻读。
具体的例子可以参考第2、3节,不再举例。

参考:

猜你喜欢

转载自blog.csdn.net/tb3039450/article/details/66475638