行锁
我们提供的服务有:成都网站建设、成都网站制作、微信公众号开发、网站优化、网站认证、瑞丽ssl等。为成百上千企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的瑞丽网站制作公司
- Record Locks
- 记录锁是索引记录上的锁,例如SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;防止任何其他事务插入,更新或删除t.c1的值为10的行
- 记录锁始终锁定索引记录,如果一个表没有定义任何的索引,像这种情况,innodb会创建一个隐藏的聚簇索引并且使用此索引进行记录锁定
- 需要注意的是:
- innodb的记录锁是针对索引加锁,不是针对物理记录加锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,将出现锁冲突
- Gap Locks
- 间隙锁是锁定索引记录之间的间隙,或锁定第一个索引记录之前或最后一个索引记录之后的间隙上。。例如 SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;由于范围内所有现有值之间的间隔都被锁定,因此可以防止其他事务向列t.c1中插入值15,无论该列中是否已有任何此类值。
- 对于使用唯一索引锁定行的语句,不需要使用间隙锁(这不包括搜索条件仅包括多列唯一索引的一些列的情况; 在这种情况下,确实会出现间隙锁定),例如,如果id列是一个唯一索引,那么下面的语句只会在id=100的那行上面加一个索引记录锁,而不会关心别的会话(session)是否在前面的间隙中插入数据。
- SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;
- 如果id没有索引或者没有唯一索引,则该语句将锁定前述的间隙
- 间隙锁的主要作用,就是和记录锁组成Next-key锁,解决幻读问题
- 间隙锁在不同的隔离级别下,有着不同的作用范围,能发挥间隙锁作用的,是’REPEATTABLE READ’隔离级别,在这个级别下使用带有间隙锁的Next-Key锁,解决了幻行的问题。这个涉及到了事务隔离级别和一致读的相关信息,后面我也会更新对应的文章
- Next-Key Locks
- next-key锁是索引记录上的记录锁和索引记录之前的间隙上的间隙锁的组合,也就是相当于Record Locks+Gap Locks
- InnoDB以这种形式实现行级锁,当它查找或扫描表索引的时候,它会在遇到的索引记录上设置共享或排它锁。因此,行级锁实际上是索引记录锁。next-key锁同样会影响索引记录之前的间隙。就是说,next-key 锁就是一个索引记录锁加上索引记录前间隙的间隙锁。如果一个会话拥有记录 R 的索引上面的一个共享锁或独占锁,另一个会话不能在索引顺序中的R之前的间隙中插入新的索引记录。
- 下面我们来看一个表
- mysql> create table goods(
- -> id int not null auto_increment primary key,
- -> title varchar(32) not null default '' comment '商品名称',
- -> classify tinyint not null default 0 comment '商品类型',
- -> index
idx_classify
(classify
) - -> )engine=innodb charset=utf8;
- mysql> insert into goods (
title
,classify
) values ('商品1',1),('商品2',3),('商品3',5),('商品4',8),('商品5',10),('商品6',1),('商品7',3),('商品8',5),('商品9',8),('商品10',10); - mysql> select * from goods;
- +----+----------+----------+
- | id | title | classify |
- +----+----------+----------+
- | 1 | 商品1 | 1 |
- | 2 | 商品2 | 3 |
- | 3 | 商品3 | 5 |
- | 4 | 商品4 | 8 |
- | 5 | 商品5 | 10 |
- | 6 | 商品6 | 1 |
- | 7 | 商品7 | 3 |
- | 8 | 商品8 | 5 |
- | 9 | 商品9 | 8 |
- | 10 | 商品10 | 10 |
- +----+----------+----------+
- 10 rows in set (0.00 sec)
- mysql> select distinct(classify) from goods;
- +----------+
- | classify |
- +----------+
- | 1 |
- | 3 |
- | 5 |
- | 8 |
- | 10 |
- +----------+
- 5 rows in set (0.02 sec)
- #在REPEATTABLE READ隔离级别下,执行查询时,因为Next-Key锁存在,写Next-Key的锁定范围如下
- (-∞,1) 锁定索引项1和1之前的间隙,因为1之前没有其他索引项,所以负无穷
- (1,3) 锁定1和3之前的间隙,不包括1,包括3
- (3,5) 同上
- (5,8) 同上
- (8,10) 同上
- (10,∞) 锁定索引项10和10之后的间隙,因为10之后没有其他索引项,所以为正无穷
- 下面我们就用一个demo来验证一下
- Session1
- mysql> start transaction;
- Query OK, 0 rows affected (0.00 sec)
- mysql> select * from goods where classify=3 for update;
- +----+---------+----------+
- | id | title | classify |
- +----+---------+----------+
- | 2 | 商品2 | 3 |
- | 7 | 商品7 | 3 |
- +----+---------+----------+
- 2 rows in set (0.00 sec)
- #对于辅助索引,其加的是Next-Key锁,锁定的范围是(1,3),特别需要注意的是,innodb存储引擎还会对辅助索引下一个键值加上gab lock,即还有一个辅助索引范围(3,5)的锁
- Session2
- mysql> start transaction;
- Query OK, 0 rows affected (0.00 sec)
mysql> insert into goods (title
,classify
) select '商品11',4; - #这时候可以看到session2给阻塞了,因为session1的Next-Key的锁定范围是(1,3),(3,5),正好包含了4
- mysql> insert into goods (
title
,classify
) select '商品11',6; - Query OK, 1 row affected (0.00 sec)
- Records: 1 Duplicates: 0 Warnings: 0
- 插入classify=6的就立刻成功了, 因为6不在(1,3),(3,5)的范围内
- Insert intention Locks
- Insert intention 锁是插入行之前由INSERT操作设置的一种间隙锁。。此锁表示要插入的意图是多个事务插入到相同的索引间隙时, 如果它们没有插入到间隙中的同一位置, 则不必等待对方。。假设存在值为4和7的索引记录。两个事务分别尝试插入5和6,分别用插入意向锁锁住4和7之间的间隙,然后再取得插入行的排它锁,但是相互不会阻塞,因为这些行是不冲突的。
- AUTO-INC Locks
- AUTO-INC锁是由插入到带有 AUTO_INCREMENT 列的表中的事务所采取的特殊表级锁。。一个最简单的例子,如果一个事务正在向表中插入值,则任何其他事务必须等待对该表执行自己的插入,以便第一个事务插入的行接收连续的主键值。
- Predicate Locks for Spatial Indexes
- innodb支持空间索引,如果使用Next-Key来支持空间索引,则不能满足要求,这是因为普通的索引都是键值类型,意味着索引存在一个方向,这个方向是单向的,要不升序要不降序,这个方向的存在,使得数据库存储引擎可以利用索引进行常规的范围查询
- 但是在空间数据类型上面,这个单向的有序变得失去了作用,因为空间数据是多维多向的,是以区域或空间为范围的,没有确定的方向顺序,所以单向的Next-Key满足不了要求
- 空间索引是建立爱MBR上的,innodb为索引项的MBR增加了一个谓词锁,实现空间索引上的并发控制