加载中…
个人资料
你若盛开_蝴蝶自来
你若盛开_蝴蝶自来
  • 博客等级:
  • 博客积分:0
  • 博客访问:229,763
  • 关注人气:7
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

MySQL InnoDB锁机制之Gap Lock、Next-Key Lock、Record Lock解析

(2015-05-30 23:29:16)
分类: MySQL

MySQL InnoDB支持三种行锁定方式:

l   行锁(Record Lock:锁直接加在索引记录上面,锁住的是key

l   间隙锁(Gap Lock:锁定索引记录间隙,确保索引记录的间隙不变。间隙锁是针对事务隔离级别为可重复读或以上级别而已的。

l   Next-Key Lock :行锁和间隙锁组合起来就叫Next-Key Lock

 

默认情况下,InnoDB工作在可重复读隔离级别下,并且会以Next-Key Lock的方式对数据行进行加锁,这样可以有效防止幻读的发生。Next-Key Lock是行锁和间隙锁的组合,当InnoDB扫描索引记录的时候,会首先对索引记录加上行锁(Record Lock),再对索引记录两边的间隙加上间隙锁(Gap Lock)。加上间隙锁之后,其他事务就不能在这个间隙修改或者插入记录。

 

Gap LockInnoDB的唯一作用就是防止其他事务的插入操作,以此防止幻读的发生。

 

1、     行锁(Record Lock

行锁锁定的是索引记录,而不是行数据,也就是说锁定的是key

2、     间隙锁(Gap Lock

例如:

create table test(id int,v1 int,v2 int,primary key(id),key `idx_v1`(`v1`))Engine=InnoDB DEFAULT CHARSET=UTF8;

该表的记录如下:

+----+------+------+

| id | v1   | v2   |

+----+------+------+

1 |    1 |    0 |

2 |    3 |    1 |

3 |    4 |    2 |

5 |    5 |    3 |

7 |    7 |    4 |

| 10 |    9 |    5 |

 

间隙锁(Gap Lock)一般是针对非唯一索引而言的,test表中的v1(非唯一索引)字段值可以划分的区间为:

-,1

1,3

3,4

4,5

5,7

7,9

9, +∞)

假如要更新v1=7的数据行,那么此时会在索引idx_v1对应的值,也就是v1的值上加间隙锁,锁定的区间是(5,7)和(7,9)。同时找到v1=7的数据行的主键索引和非唯一索引,对key加上锁。

3、     后码锁(Next-Key Lock

记录锁和间隙锁的结合,对于InnoDB中,更新非唯一索引对应的记录(在这里来说是更新v1字段的值),会加上Next-Key Lock。如果更新记录为空,就不能加记录锁,只能加间隙锁。

 

举个例子(事务隔离级别为MySQL默认的可重复读)

MySQL <wbr>InnoDB锁机制之Gap <wbr>Lock、Next-Key <wbr>Lock、Record <wbr>Lock解析

为什么TRANSACTION 2insert操作会被阻塞,产生等待呢?这是因为TRANSACTION 2插入的v1值为6TRANSACTION 1的锁定区间(5,9)内。而TRANSACTION 1插入的v1值不在TRANSACTION 2的锁定区间(5,7)内,故可以成功插入。不仅仅insert操作, update操作也一样会被锁住,从而锁等待超时。

 

4、     锁选择

1)、如果更新条件没有走索引,例如执行”update from t1 set v2=0 where v2=5;” ,此时会进行全表扫描,扫表的时候,要阻止其他任何的更新操作,所以上升为表锁。

2)、如果更新条件为索引字段,但是并非唯一索引(包括主键索引),例如执行“update from t1 set v2=0 where v1=9;” 那么此时更新会使用Next-Key Lock。使用Next-Key Lock的原因:

a)、首先要保证在符合条件的记录上加上排他锁,会锁定当前非唯一索引和对应的主键索引的值;

b)、还要保证锁定的区间不能插入新的数据。

3)、如果更新条件为唯一索引,则使用Record Lock(记录锁)。

 

InnoDB根据唯一索引,找到相应记录,将主键索引值和唯一索引值加上记录锁。但不使用Gap Lock(间隙锁)。

5、     间隙锁(Gap Lock

 

加后码锁的时候,并没有锁住间隙两端的记录(这里的两端分别是5,95,7),那么两端的记录是可以更新的,但是如果更新两端的记录会影响到间隙锁,那么操作会被挂起,等待间隙锁释放。

MySQL <wbr>InnoDB锁机制之Gap <wbr>Lock、Next-Key <wbr>Lock、Record <wbr>Lock解析


看以下演示:

MySQL <wbr>InnoDB锁机制之Gap <wbr>Lock、Next-Key <wbr>Lock、Record <wbr>Lock解析

MySQL <wbr>InnoDB锁机制之Gap <wbr>Lock、Next-Key <wbr>Lock、Record <wbr>Lock解析

为什么在左侧值为4,右侧值为7的时候,有时候操作会被挂起,有时候操作不会挂起呢?解释如下:

MySQL <wbr>InnoDB锁机制之Gap <wbr>Lock、Next-Key <wbr>Lock、Record <wbr>Lock解析

当插入左侧值的时候,即插入v1=4的时候,要求插入的id值小于id=3的范围。当v1=4的记录有多条的时候,插入的id值要小于其中的最大id值。则可以成功插入;

当插入右侧值的时候,即插入v1=7的时候,要求插入的id值要大于id=7的范围。当v1=7的记录有多条的时候,插入的id值要大于其中的最小id值。则可以成功插入。








0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有