MVVC 实现:排他锁+undolog+版本事务链+一致性read-view视图+版本事务链匹配规则
在 InnoDB
存储引擎中, 就是对非锁定读的实现。如果读取的行正在执行 DELETE
或 UPDATE
操作,这时读取操作不会去等待行上锁的释放。相反地,InnoDB
存储引擎会去读取行的一个快照数据,对于这种读取历史数据的方式,我们叫它快照读 (snapshot read)
在 Repeatable Read
和 Read Committed
两个隔离级别下,如果是执行普通的 select
语句(不包括 select ... lock in share mode
,select ... for update
)则会使用 一致性非锁定读(MVCC)
。并且在 Repeatable Read
下 MVCC
实现了可重复读和防止部分幻读
在锁定读下,读取的是数据的最新版本,这种读也被称为 当前读(current read)
。锁定读会对读取到的记录加锁
select ... lock in share mode
:对记录加 S
锁**(共享锁)**,其它事务也可以加S
锁,如果加 x
锁则会被阻塞select ... for update
、insert
、update
、delete
:对记录加 X
锁**(排他锁)**,且其它事务不能加任何锁如果执行的是下列语句,就是
select ... lock in share mode
select ... for update
insert
、update
、delete
操作InnoDB
在实现Repeatable Read
时,如果执行的是当前读,则会对读取的记录使用 Next-key Lock
,来防止其它事务在间隙间插入数据
MVCC由三个部分实现:隐藏字段、Read View、undo log
每一行记录都会包含几个用户不可见的字段
InnoDB
会使用该 id 来生成聚簇索引undo log
主要有两个作用:
MVCC
,当读取记录时,若该记录被其他事务占用或当前版本对该事务不可见,则可以通过 undo log
读取之前的版本数据,以此实现非锁定读在 InnoDB
存储引擎中 undo log
分为两种: insert undo log
和 update undo log
:
1,首先比较DB_TRX_ID<up_limit_id,如果小于,则当前事务能看到DB_TRX_ID所在的记录,如果大于等于进入下一个判断
2,接下来判断DB_TRX_ID>=low_limit_id,如果大于等于则代表DB_TRX_ID所在的记录在Read_view生成后才出现的,那么对于当前事务肯定不可见,如果小于,则进入下一步判读
3,判断DB_TRX_ID是否在活跃事务中,如果在,则代表在Read View生成时刻,这个事务还是活跃状态,还没有commit,修改的数据,当前事务也是看不到,如果不在,则说明这个事务在Read View生成之前就已经开始commit,
readview生成的时机是不同的
RC:每次在进行快照读的时候都会生成新的readview
RR:只有第一次进行快照读的时候才会生成readview,之后的读操作斗湖用第一次生成的readview
怎么查看mysql 锁
show engine innodb status
set global inndb_status_output_lock=1;
查询既包含当前读和快照读 可能触发幻读
InnoDB存储引擎在 RR 级别下通过 MVCC和 Next-key Lock 来解决幻读问题:
1、执行普通 select,此时会以 MVCC 快照读的方式读取数据
在快照读的情况下,RR 隔离级别只会在事务开启后的第一次查询生成 Read View ,并使用至事务提交。所以在生成 Read View 之后其它事务所做的更新、插入记录版本对当前事务并不可见,实现了可重复读和防止快照读下的 “幻读”
2、执行 select…for update/lock in share mode、insert、update、delete 等当前读
在当前读下,读取的都是最新的数据,如果其它事务有插入新的记录,并且刚好在当前事务查询范围内,就会产生幻读!InnoDB 使用 Next-key Lock 来防止这种情况。当执行当前读时,会锁定读取到的记录的同时,锁定它们的间隙,防止其它事务在查询范围内插入数据。只要我不让你插入,就不会发生幻读