美文网首页
InnoDB锁定

InnoDB锁定

作者: 十年磨一剑1111 | 来源:发表于2020-09-30 11:36 被阅读0次

1. 不同的锁类型

(1) 共享锁和排他锁
Innodb 实现标准的行级锁定,其中有两种类型的锁:共享(S)锁和排他(X)锁
共享(S)锁:允许事务持有锁读取一行数据。
排他(X)锁:允许事务持有锁更新或者删除一行数据
那这个两种锁之间的关系数怎样的呢?
如果T1持有行上的共享(S)锁,那另外一个事务申请锁是怎么处理的呢?
如果T2申请的是S锁,那么就会被很快同意,那结果就是事务T1和事务T2共同持有一把S锁。
如果T2申请的是X锁,那么很快就会被拒绝。
如果事务T1持有某行的一个排他锁,那么其他事务比如T2想要申请S锁或者X锁都会被很快拒绝,换句话说,事务T2必须等待事务T1释放行上的锁。
(2) 意向锁
InnoDB支持多种粒度的锁定,行锁和表锁可以并存。举个例子,lock tables .. write 会在指定的表上加排他锁,为了支持不同级别的锁粒度,InnoDB引入了意向锁,意向锁是一种表级别的锁,它指示事务稍后对表中的行需要哪种类型的锁(共享锁或者排他锁),有两种类型的意向锁:
意向共享锁(IS):它表明某个事务试图在数据行上(Innodb行锁实际上是加在索引上的,明白这个概念很重要)加共享锁。
意向排他锁(IX): 它表明是某个事务试图在数据行上加排他锁。
举个例子: select ... lock in share mode 设置了一个IS锁,select ... for update 设置了一个IX锁。
意向锁锁定的规则如下:

  1. 某个事务在得到某张表中某行数据的共享锁之前,必须先获得一个IS锁或者更强(IX)的锁。
  2. 某个事务在得到某张表中某行数据的的排它锁之前,它必须先获取到这张表的IX锁。
    下面来总结下表上的一些锁之间的兼容性。


    图片.png

    如果一个事务正在申请的锁与现存的锁不冲突的话,就会被允许,否则需要等待存在冲突的锁被释放。如果事务请求的锁和现有的锁存在冲突的话,就会不被允许,因为这样会发生死锁。
    关于意向锁我们可以使用show engine innodb status 或者Innodb 监控可以看到类似下面的输出:

table lock table `test`.`t` trx id 10080 lock mode IX

笔者在这里做下简单的测试:
数据库版本5.7

mysql > begin;
mysql > update tb1001 set order_num = 20 where order_id = 20;
mysql > show engine innodb status;
...
...
...
2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1
MySQL thread id 114, OS thread handle 140690725353216, query id 448 localhost root starting
show engine innodb status
**TABLE LOCK table `test`.`tb1001` trx id 1900 lock mode IX**
RECORD LOCKS space id 27 page no 3 n bits 80 index PRIMARY of table `test`.`tb1001` trx id 1900 lock_mode X locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
...
...
...

上面笔者复制了部分运行结果,可以看到其中有一行ABLE LOCK table test.tb1001 trx id 1900 lock mode IX 这个就表示 tb1001 这张表上了IX锁。
(3) 行锁
行锁是一种加在索引上面的锁,比如:select c1 from t where c1 = 10 for update; 这个会阻止其他事务插入,更新或者删除t.c1=10 的行。
行锁总是加在索引记录上,即使表里面没有索引,如果表中没有索引,Innodb会隐式的创建一个聚簇索引并且使用这个索引来实现行锁。
关于行锁我们同样可以使用show engine innodb staus 或者Innodb监控工具来查看,笔者在这里简单的做下测试:

mysql > begin;
mysql > update tb1001 set order_num = 100 where order_id = 20;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql > show engine innodb status;
...
...
...
show engine innodb status
Trx read view will not see trx with id >= 1902, sees < 1902
TABLE LOCK table `test`.`tb1001` trx id 1902 lock mode IX
RECORD LOCKS space id 27 page no 3 n bits 80 index PRIMARY of table `test`.`tb1001` trx id 1902 lock_mode X locks rec but not gap
...
...
...

运行结果里面有一段 lock_mode X locks rec but not gap,表明当前update 语句在聚簇索引上加了一个行锁(笔者表中order_id 是主键索引),但是不是gap 锁(间隙锁),关于间隙锁下面会详细介绍到。
(4)** 间隙锁**
间隙锁是一种加在索引之间,或者是第一条索引记录之前或最后一条索引记录之后的一种锁。 举个例子:select c1 from t where c1 between 10 and 20 for update; 如果事务A执行了这条语句后,那么其他事务就不能插入c1=15的记录到表中,不管这条记录是否存在
间隙可能是跨越单个索引值,多个索引值,甚至是空的。
间隙锁是在执行效率和并发性之间权衡的一部分,只使用在某些事务隔离级别下。
如果使用的是唯一索引去搜索唯一的数据行,那么锁定间隙是不需要的(这不包含多列唯一索引某些列的情况,在这种情况下,会发生间隙锁定)举个例子,如果id列加了一个唯一索引那么下面的语句只会使用在id=100的索引上加行锁,其他的事务是否在前面的间隙中插入行并不重要,比如下面这条更新语句:

update  table set  name = 'aaa' where id =  100;

如果 id列不是索引或者不是唯一索引,语句会锁定间隙(是所有的间隙,小伙伴们可以测试看下)。
Innodb 中的间隙锁是 " purely inhibitive",它的唯一目的是防止其他事务插入间隙,间隙锁可以共存,一个事务加了间隙锁并不影响其他事务对相同的区间加间隙锁,间隙共享锁和间隙排他锁没有什么不一样的地方,它们不会产生冲突,并且功能是一样的。
间隙锁也可以失效或者取消,如果你的事务隔离级别是提交读或者设置了innodb_locks_unsafe_for_binlog=1(已经废弃),在这种情况下间隙锁定对搜索和索引扫描是被禁用的,它仅仅使用在外键约束检查和重复检查的情况下。
在可提交读的事务隔离级别下的其他一些特性,这里就不在多讨论了,有需要了解的可以查阅官方文档。
那关于间隙锁笔者就先说到这里。下面来介绍Next-Key Locks
(5) Next-Key Locks
next-key锁是两种锁的组合:行锁+该行记录之前的间隙。
当搜索或者扫描发生在索引上时,Innodb会执行行级别的锁定,会对遇到的索引记录设置共享或者排他锁,因此,行级锁实际上是索引记录锁。next-key锁锁定在索引记录上还会影响索引之前的间隙,那也就是说next-key锁是行锁+该行锁之前的间隙,如果一个事务在记录R上加了共享或者排他锁,那么另外一个事务就不能在记录R之前的间隙插入记录。
默认情况下Innodb 使用可重复读作为事务的隔离级别,Innodb使用next-key锁定进行搜索和索引扫描,这可以防止幻读。
关于next-key锁笔者在这里举个例子:
假设索引包含值10、11、13和20,该索引的可能的下一键锁定涵盖以下间隔,其中,圆括号表示排除区间断点,方括号表示包括端点:
(negative infinity,10]
(10,11]
(11,13]
(13,20]
(20,positive infinity)
对于最后一个区间,positive infinity 的记录值实际上是不存在的,因此,这个下一键锁定仅锁定跟随最大索引值的间隙。
关于下一键锁定事务数据我们可以使用show engine innodb status 查看输出:

RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t`
trx id 10080 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 8000000a; asc     ;;
 1: len 6; hex 00000000274f; asc     'O;;
 2: len 7; hex b60000019d0110; asc        ;;

(6)插入意向锁
插入意向锁是一种间隙锁,它是在insert操作之前加的一种锁。多个事务如果在相同的间隙插入数据只要它们插入的不是同一个位置就不需要相互等待,比如这里有4到7的索引记录,不同的事务想要插入值5和6,相应的,在获得插入行的排他锁之前会锁定4到7之间的间隙,不过这两个事务不会有冲突,因为他们的行是不相同的。下面举个例子来体验下插入意向锁:

//session1
mysql > begin
mysql > select * from tb1001 where order_id  > 30 for update;
mysql > show engine innodb status;
insert into tb1001 values (31,20,31)
------- TRX HAS BEEN WAITING 14 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 35 page no 3 n bits 80 index PRIMARY of table `test`.`tb1001` trx id 2842 lock_mode X locks gap before rec insert intention waiting

(7) 自动加锁
innodb 表中如果有自动增长的列(实际上如果没有的话也会自动创建一个),在最简单的情况下,如果一个事务正在向表中插入值,那么其他事务必须等待自己在该表中进行插入,以便第一个事务插入的行数是连续的主键值。

关于InnoDB的行锁定就简单介绍到这里了, 如果有错误的地方欢迎大家指出来。不过建议大家对有疑问的地方多测试,测试结果可以使用show engine innodb status 和查阅information_schema 库中的innodb_locks 和innodb_lock_waits表进行相关的分析。
另外,就是本篇文章是翻译的官方文档,再加上笔者的一些理解。

相关文章

  • InnoDB锁定

    1. 不同的锁类型 (1) 共享锁和排他锁Innodb 实现标准的行级锁定,其中有两种类型的锁:共享(S)锁和排他...

  • 校招面试题mysql锁总结

    目录 锁定义 锁分类 读锁和写锁 表锁和行锁 InnoDB共享锁和排他锁 InnoDB意向锁和排他锁 InnoDB...

  • MySQL探秘(七):InnoDB行锁算法

     在上一篇《InnoDB一致性非锁定读》中,我们了解到InnoDB使用一致性非锁定读来避免在一般的查询操作(SEL...

  • MySQL架构

    参考原文 InnoDB与MyISAM存储引擎对比 InnoDB支持事务、外键、行锁;支持非锁定读,即默认读取操作不...

  • 数据库引擎

    InnoDB 存储引擎 InnoDB 是事务型数据库的首选引擎,支持事务安全表 (ACID),支持行锁定和外键。M...

  • 一致性非锁定读和一致性锁定读

    一致性非锁定读(consistent nonlocking read)一致性非锁定读是指InnoDB存储引擎通过多...

  • 3.行级锁

    行级锁介绍 InnoDB存储引擎实现 一. InnoDB的行级锁,按照锁定范围来说,分为三种: 1.记录锁(Rec...

  • InnoDB 悲观锁实现

    InnoDB中的select .. for update语句: 排它锁的选择: eg:# 只锁定message_i...

  • InnoDB加锁分析

    InnoDB加锁分析 在事务的并发控制,MySQL使用MVCC来支持快照读和使用加锁来支持锁定读两种方式,锁定通过...

  • Mysql InnoDB

    InnoDB是一个事务型的存储引擎,有行级锁定和外键约束。 Innodb引擎提供了对数据库ACID事务的支持,并且...

网友评论

      本文标题:InnoDB锁定

      本文链接:https://www.haomeiwen.com/subject/jcmduktx.html