Mysql.Note3

来源:互联网 发布:淘宝买到三无产品 编辑:程序博客网 时间:2024/06/09 14:41

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

· 行锁(Record Lock:锁直接加在索引记录上面。

· 间隙锁(Gap Lock:锁加在不存在的空闲空间,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。

· Next-Key Lock:行锁与间隙锁组合起来用就叫做Next-Key Lock

默认情况下,InnoDB工作在可重复读隔离级别下,并且以Next-Key Lock的方式对数据行进行加锁,这样可以有效防止幻读的发生。Next-Key Lock是行锁与间隙锁的组合,这样,当InnoDB扫描索引记录的时候,会首先对选中的索引记录加上行锁(Record Lock,再对索引记录两边的间隙(向左扫描扫到第一个比给定参数小的值,向右扫描扫描到第一个比给定参数大的值,然后以此为界,构建一个区间)加上间隙锁(Gap Lock如果一个间隙被事务T1加了锁,其它事务是不能在这个间隙插入记录的


举个例子:
task_queue
Id           taskId
1              2
3              9
10            20
40            41

开启一个会话: session 1

sql> set autocommit=0;

   ##

取消自动提交


sql> delete from task_queue where taskId = 20;
sql> insert into task_queue values(20, 20);

在开启一个会话: session 2

sql> set autocommit=0;

   ##

取消自动提交


sql> delete from task_queue where taskId = 25;
sql> insert into task_queue values(30, 25);

在没有并发,或是极少并发的情况下,这样会可能会正常执行,在Mysql中, 事务最终都是穿行执行, 但是在高并发的情况下, 执行的顺序就极有可能发生改变, 变成下面这个样子:
sql> delete from task_queue where taskId = 20;
sql> delete from task_queue where taskId = 25;
sql> insert into task_queue values(20, 20);
sql> insert into task_queue values(30, 25);

个时候最后一条语句:insert into task_queue values(30, 25); 执行时就会爆出死锁错误。因为删除taskId = 20这条记录的时候,20 --  41 都被锁住了, 他们都取得了这一个数据段的共享锁, 所以在获取这个数据段的排它锁时出现死锁。

间隙锁在InnoDB的唯一作用就是防止其它事务的插入操作,以此来达到防止幻读的发生,所以间隙锁不分什么共享锁与排它锁。另外,在上面的例子中,我们选择的是一个普通(非唯一)索引字段来测试的,这不是随便选的,因为如果InnoDB扫描的是一个主键、或是一个唯一索引的话,那InnoDB只会采用行锁方式来加锁,而不会使用Next-Key Lock的方式,也就是说不会对索引之间的间隙加锁,仔细想想的话,这个并不难理解,大家也可以自己测试一下。

 

要禁止间隙锁的话,可以把隔离级别降为读已提交,或者开启参数innodb_locks_unsafe_for_binlog

 

innodb中幻读与mvcc和间隙锁分析:

首先读分为: 
快照读 
select * from table where ?;

当前读:特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。 
select * from table where ? lock in share mode; 
select * from table where ? for update; 
insert into table values (…); 
update table set ? where ?; 
delete from table where ?;

对于快照读来说,幻读的解决是依赖mvcc解决。而对于当前读则依赖于gap-lock解决。

以上就是innodb中幻读与mvcc和间隙锁分析的全文介绍,希望对您学习和使用数据库有所帮助.

原创粉丝点击