您的当前位置:首页正文

mysql mvcc

2024-11-08 来源:个人技术集锦

mysql MVCC

MVVC 实现:排他锁+undolog+版本事务链+一致性read-view视图+版本事务链匹配规则

一致性非锁定读

InnoDB 存储引擎中, 就是对非锁定读的实现。如果读取的行正在执行 DELETEUPDATE 操作,这时读取操作不会去等待行上锁的释放。相反地,InnoDB 存储引擎会去读取行的一个快照数据,对于这种读取历史数据的方式,我们叫它快照读 (snapshot read)

Repeatable ReadRead Committed 两个隔离级别下,如果是执行普通的 select 语句(不包括 select ... lock in share mode ,select ... for update)则会使用 一致性非锁定读(MVCC)。并且在 Repeatable ReadMVCC 实现了可重复读和防止部分幻读

锁定读

在锁定读下,读取的是数据的最新版本,这种读也被称为 当前读(current read)。锁定读会对读取到的记录加锁

  • select ... lock in share mode:对记录加 S 锁**(共享锁)**,其它事务也可以加S锁,如果加 x 锁则会被阻塞
  • select ... for updateinsertupdatedelete:对记录加 X 锁**(排他锁)**,且其它事务不能加任何锁

如果执行的是下列语句,就是

  • select ... lock in share mode
  • select ... for update
  • insertupdatedelete 操作

InnoDB 在实现Repeatable Read 时,如果执行的是当前读,则会对读取的记录使用 Next-key Lock ,来防止其它事务在间隙间插入数据

MVCC由三个部分实现:隐藏字段、Read View、undo log

第一个部分——隐藏字段

每一行记录都会包含几个用户不可见的字段

  • DB_TRX_ID——创建或者最后一次修改记录的事务id
  • DB_ROW_ID——如果没有设置主键且该表没有唯一非空索引时,InnoDB 会使用该 id 来生成聚簇索引
  • DB_ROLL_PTR——回滚指针——undolog

第二部分——undolog (回滚日志-保存历史版本状态)

undo log 主要有两个作用:

  • 当事务回滚时用于将数据恢复到修改前的样子
  • 另一个作用是 MVCC ,当读取记录时,若该记录被其他事务占用或当前版本对该事务不可见,则可以通过 undo log 读取之前的版本数据,以此实现非锁定读

InnoDB 存储引擎中 undo log 分为两种: insert undo logupdate undo log

第三部分——readview(事务在进行快照读的时候产生的读视图)

  • trx_list——当前事务活跃的ID
  • up_limit_id——列表中事务最小的ID
  • low_limit_id——系统尚未分配的下一个事务ID

可见性算法

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,

RR 与 RC

readview生成的时机是不同的

RC:每次在进行快照读的时候都会生成新的readview

RR:只有第一次进行快照读的时候才会生成readview,之后的读操作斗湖用第一次生成的readview

怎么查看mysql 锁

show engine innodb status

set global inndb_status_output_lock=1;

查询既包含当前读和快照读 可能触发幻读

MVCC➕Next-key-Lock 防止幻读

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 来防止这种情况。当执行当前读时,会锁定读取到的记录的同时,锁定它们的间隙,防止其它事务在查询范围内插入数据。只要我不让你插入,就不会发生幻读

Top