MySQL的MVCC

MySQL的MVCC

1. 什么是MVCC

MVCC中文是多版本并发控制,顾名思义,是一种提高并发的技术。根据逻辑,在并发上只有读读是不阻塞的,而读写、写读、写写是需要阻塞。但是在MVCC出来之后,只有写写才能阻塞,其他三个都可以并行操作。这也是InnoDB存储引擎受欢迎的原因之一。

InnoDB并不是单纯的行级锁,而是同时实现了MVCC,所以也可以认为MVCC是行级锁的另一种形式。MVCC有多种实现方式:乐观并发控制、悲观并发控制。同时MVCC只能在READ COMMITREPEATABLE READ 两个隔离级别下工作。因为 READ UNCOMMIT 总是读取最新的行,并不符合当前事务版本的数据行,SERIALIZABLE是对所有读的行都加锁。

2. READ VIEW 和 SNAPSHOT

InnoDB为实现MVCC所使用的内部快照,RR(REPEATABLE READ)隔离级别下在第一次查询时创建READ VIEW,RC(READ COMMITTED)隔离级别下会在每次查询时创建read view

先看一下相关的概念:

InnoDB支持MVCC多版本,其中READ COMMITREPEATABLE READ隔离级别是利用consistent read view(一致读视图)方式支持的。 所谓consistent read view就是在某一时刻给事务系统trx_sysSNAPSHOT(快照),把当时trx_sys状态(包括活跃读写事务数组)记下来,之后的所有读操作根据其事务ID(即trx_id)与SNAPSHOT中的trx_sys的状态作比较,以此判断READ VIEW对于事务的可见性。

REDA VIEW 说白了就是为了做可见性判断的,解释为 本事务不可见的其他活跃事务

  • READ COMMIT:事务中的每一个select都会生成一个快照。
  • REPEATABLE READ:只会在该事务中第一次select生成后创建快照,将当前系统中活跃的其他事务记录下来。

3. undo log

undo log 是 MVCC 事务特性的重要组成部分,做了变更操作时就会产生 undo logundo log 默认被记录到系统表空间中,但从5.6开始,也可以使用独立的 undo log 表空间。

undo log 记录中存储的是老版本的数据,当一个旧的事务需要读取事务时,为了能够获取老版本的数据,需要顺着undo log 的链找到满足其可见性的记录。版本链很长时,会很耗时。

  • insert:insert操作在事务提交前支队当前事务可见,产生的undo log 可以在事务提交后直接删除。
  • update/delete:需要维护多版本信息,在INNODB里,updatedelete产生的日志会被归为update_undo

4. 行数据的三个字段

4.1. DB_TRX_ID - 事务ID

6字节,用来表示最近一次对本行记录做修改的事务(insert/update)的标识符,也是最后一次修改本行记录的事务id。

4.2. DB_ROLL_PTR - 回滚指针

7字节,指写入回滚段的撤销日志记录,如果一行记录被更新,则撤销日志记录 包含 重建该记录被更新之前内容 所必须的信息。

4.3. DB_ROW_ID

6字节,如果没有指定主键索引,InnoDB会为每一行生成一个单调递增的ID。

5. 可见性比较算法

  • 要读取的行的最后提交事务id = trx_id_current
  • 当前新开事务id = new_id
  • 当前新开事务创建的快照 read view 中 最早的事务id 为 up_limit_id,最迟的事务id为 low_limit_id(low_limit_id = 未开启的事务id = 当前最大事务id + 1)

步骤:

  1. trx_id_current < up_limit_id:新事物在读取该行记录时,稳定的事务ID小于最小活跃ID,就可以直接获取该可见的值。
  2. trx_id_current >= trx_id_last:记录的稳定事务在本次新事物创建之后才开启的,所以当前的值并不可见。(这里指的RR隔离级别)。
  3. trx_id_current <= trx_id_current <= trx_id_last:该行记录所在事务在本次新事务创建的时候处于活动状态,从up_limit_id到low_limit_id进行遍历,如果等于他们中的某个事务id,则不可见。否则可见。
  4. 接着3中的不可见,从该行记录的DB_ROLL_PTR指针所指向的回滚段中取出最新的undo log的版本号,将它赋值该trx_id_current,然后重新判断。

6. 当前读和快照读

RR隔离级别是通过行排他锁+MVCC实现的,不仅可以保证可重复读,还可以部分防止幻读,并非完全防止。

事务B在事务A执行中,插入了一条数据并提交,事务A再次查询,虽然读取的undo log 中不存在,但是update 或者 delete 这条数据可以成功。

6.1. 当前读

当前读指的是加锁的读或者是增删改

  • select ······ lock in share mode
  • select ······ for update
  • insert
  • update
  • delete

当前读是通过record lock(记录锁) 和 gap lock(间隙锁)来实现的。

6.2. 快照读

简单的select,并不包含加锁。

快照读是通过MVCC+undo log实现的。

7. MVCC特点

  • 每行数据都存在一个版本,每次数据更新时都更新该版本。
  • 修改时,copy当前的版本,任意更改,各个事务之间保证隔离。
  • 保存时比较版本号,如果commit成功,覆盖原来记录,如果失败,则回滚。
  • 根据版本号判断是否保存成功,优点类似于乐观锁的原理。
  • 事务以排他锁的形式修改原始数据。
  • 把修改前的数据存放在undo log,通过回滚指针与主数据关联。
  • 如果修改失败,则回复undo log 中的数据,也就是回滚。

翻译自:https://segmentfault.com/a/1190000012650596

推荐一个宝藏up主小姐姐:https://www.bilibili.com/video/BV1Vk4y1k7KQ?from=search&seid=17055943543545838942

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值