mysql幻读

142 阅读2分钟
在mysql中,提供了两种事务隔离技术,第一个是mvcc,第二个是next-key技术

快照读(snapshot read)

简单的select操作(不包括 select ... lock in share mode, select ... for update)

当前读(current read)

select ... lock in share mode
select ... for update
insert
update
delete
在RR级别下,快照读是通过MVVC(多版本控制)和undo log来实现的,
当前读是通过加record lock(记录锁)和gap lock(间隙锁)来实现的组合是next-key lock

什么是mvcc

mvcc全称是multi version concurrent control(多版本并发控制)。
mysql把每个操作都定义成一个事务,每开启一个事务,系统的事务版本号自动递增。
每行记录都有两个隐藏列:创建版本号和删除版本号

select:事务每次只能读到创建版本号小于等于此次系统版本号的记录,
同时行的删除版本号不存在或者大于当前事务的版本号。

update:插入一条新记录,并把当前系统版本号作为行记录的版本号,
同时保存当前系统版本号到原有的行作为删除版本号。

delete:把当前系统版本号作为行记录的删除版本号

insert:把当前系统版本号作为行记录的版本号

MVCC解决了基于快照读下的幻读

什么是next-key锁

Next-Key Lock是Gap Lock(间隙锁)和Record Lock(行锁)的结合版,
都属于Innodb的锁机制

排它锁:X锁、 写锁,事务A对一个资源加了X锁后只有A本身能
对该资源进行读和写操作,其他事务对该资源的读和写操作都将被阻塞,直到A释放锁为止  

共享锁:S锁、 读锁, 事务A锁定的数据其他事务可以共享读该资源,
但不能写,直到事务A释放

InnoDB 默认开启间隙锁,  innodb_locks_unsafe_for_binlog
参数表示是否禁用Gap Lock间隙锁,默认值0 关闭

锁选择

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

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

使用Next-Key Lock的原因:
首先要保证在符合条件的记录上加上排他锁,会锁定当前非唯一索引和对应的主键索引的值;
还要保证锁定的区间不能插入新的数据。
如果更新条件为唯一索引,则使用Record Lock(记录锁)。
InnoDB根据唯一索引,找到相应记录,将主键索引值和唯一索引值加上记录锁。
但不使用Gap Lock(间隙锁)