MySQL Innodb存储引擎中间隙锁防止幻读的产生
如你我所知,MySQL默认的隔离级别是Repeatable Read,同时知道这种隔离级别是有幻读产生的,但是真的会出现幻读吗?
- 答案:在RR的隔离级别下,Innodb使用MVCC和 next-key locks(行锁和间隙锁的组合)解决幻读,MVCC解决的是普通读(快照读)的幻读,next-key locks解决的是当前读情况下的幻读。
Gap Lock在InnoDB的唯一作用就是防止其他事务的插入操作,以此防止幻读的发生。
Innodb自动使用间隙锁的条件:
(1)必须在Repeatable Read级别下
(2)检索条件必须有索引(没有索引的话,mysql会全表扫描,那样会锁定整张表所有的记录,包括不存在的记录,此时其他事务不能修改不能删除不能添加)
间隙锁:
间隙锁在InnoDB的唯一作用就是防止其它事务的插入操作,以此来达到防止幻读的发生,所以间隙锁不分什么共享锁与排它锁。 默认情况下,InnoDB工作在Repeatable Read隔离级别下,并且以Next-Key Lock的方式对数据行进行加锁,这样可以有效防止幻读的发生。Next-Key Lock是行锁与间隙锁的组合,当对数据进行条件,范围检索时,对其范围内也许并存在的值进行加锁!当查询的索引含有唯一属性(唯一索引,主键索引)时,Innodb存储引擎会对next-key lock进行优化,将其降为record lock,即仅锁住索引本身,而不是范围!若是普通辅助索引,则会使用传统的next-key lock进行范围锁定!
要禁止间隙锁的话,可以把隔离级别降为Read Committed,或者开启参数innodb_locks_unsafe_for_binlog。
快照读和当前读
在MVCC并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。
- 快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。
- 当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。
- 在一个支持MVCC并发控制的系统中,哪些读操作是快照读?哪些操作又是当前读呢?以MySQL InnoDB为例:
- 快照读:简单的select操作,属于快照读,不加锁。(当然,也有例外,下面会分析)
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 ?;
- 快照读:简单的select操作,属于快照读,不加锁。(当然,也有例外,下面会分析)