Mysql系列(四)彻底理解MVCC+行锁+表锁+间隙锁

一. 什么是MVCC

MVCC(Multi-Version Concurrency Control),即多版本并发控制。不使用锁,主要是用来提高数据库的并发性能;算是一种概念,不同的数据库有不同的实现方式,本文主要介绍mysql的innodb引擎中的实现方式。

在mysql的innodb中,前面我们有篇文章《Mysql系列(二)Mysql事务四大隔离级别详解&演示》分析了4种隔离级别,以及每种隔离级别下导致的问题,脏读、不可重复读、幻读。其中不可重复读、幻读就是使用MVCC来解决的。

二.什么是行锁、表锁、间隙锁

首先锁的存在,目的是为了在并发场景下,保持数据的安全、一致。
并发场景有:

  • 读-读 :此并发场景不需要进行并发控制,也就是不需要加锁。
  • 读-写 :此并发场景需要并发控制,不然就会出现脏读,幻读,不可重复读的问题。
  • 写-写 :此并发场景需要并发控制,不然就会出现更新丢失的问题。

进行并发控制,常规手段就是加锁,不管是咋java业务代码中,还是mysql数据库本身,都有实现自己的锁,其中mysql的锁有以下几种:

  • 行锁:锁住表中的一行;比如 update user set name=‘张三’ where id=1;会锁住id=1的那一行数据,其他事务再想更新,就只能等前一个事务释放锁。
  • 表锁:锁住整个表,比如update user set name=‘张三’;由于没有加where条件,此更新sql会对整个表进行更新,也就是会锁住整个表。
  • 间隙锁:比如事务A执行update user set name=‘张三’ where id >1 and id<4; 假如表中只有id=1、2 两条数据,A事务还没提交,那么此时事务B再次插入一条id=3的数据,理论上是允许的,但是实际上是B只能等A提交,因为事务A执行的是id>1and id<4,范围涵盖了id=3的,也即是把id=3的这个间隙也给锁了,叫做间隙锁

除了这3种锁,还有乐观锁、悲观锁、记录锁、自增锁、意向锁;

三. MVCC与各种锁的关系

既然可以使用行锁、表锁、间隙锁来保证数据操作的安全性,那么还要MVCC的出现是为何呢? 实际是因为在性能方面还有优化的空间

虽然使用锁可以保证数据安全,但是毕竟加了锁就意味着并发性能的降低,因此,能不使用锁就尽量不使用锁。在某些场景下,MVCC可以在比使用锁更快。

在读-读、读-写、写-写这3种并发场景中,读-写 可以不使用锁,而是使用MVCC来实现数据的并发操作以及安全一致性

因此,mysql是同时使用了MVCC+行锁、表锁、间隙锁来保证了数据安全,又尽可能大的实现了性能最优化。

四. MVCC的实现原理

4.1 多版本

那么不使用锁,MVCC是如何更高效的解决读-写这种并发场景下的数据安全呢?
我们知道,事务在执行失败时,会将数据回滚为上个版本,而MVCC叫做多版本并发控制,核心概念就在版本上,也就是说数据库存储了多个版本的数据。

多个版本整体上分为两类:最新版本历史版本
这也牵扯出来另外两个概念:

  • 快照读:读取的是数据库种历史版本的数据;
    常规的select * from user ;属于是快照读;
  • 当前读:读取的是数据库种最新版本的数据;当前读的操作有:
    select * from user in share mode(共享锁),;
    select * from user for update;
    update, insert ,delete(排他锁)

那么多个版本,mysql是如何存储的呢?

innodb存储引擎中,我们存在表中的数据,除了我们设置的业务字段,另外还有3个默认字段,如下图末尾3个:
在这里插入图片描述

  • DB_TRX_ID: 事务id,存的是创建事务的id,或者最后一次更新事务的id;
  • DB_ROW_ID: 主键id,建表时如果没设置主键,则此字段会成为主键发挥作用;
  • DB_ROLL_PTR: 回滚指针,指向上一个版本的数据,如果没有上个版本,则为null。

其中,DB_ROLL_PTR结合undo log实现。

4.2 undo log

undo log称为回滚日志,是InnoDB MVCC事务特性的重要组成部分,存在形式就是一种日志文件。

undo log的数据结构,非常复杂,可以简单理解为链表,链表头部存储最新版本,尾部存储最早版本。通过遍历链表,就可以找到对应版本的数据。
在这里插入图片描述
大多数对数据的变更操作包括INSERT/DELETE/UPDATE,其中,

  • INSERT操作使用insert_undo,因为新插入就只有一个版本,因此产生的Undo日志可以在事务提交后直接删除;
  • 而对于UPDATE/DELETE则需要维护多版本信息,在InnoDB里,UPDATE和DELETE操作产生的Undo日志被归成一类,即update_undo;mvcc使用的undolog,就是update_undo。

只有undolog,还不足以实现mvcc,因为既然undolog维护了那么多版本,遍历的时候,应该去找哪一个版本呢?这里必然牵扯到一种规则,这种规则在不同的数据库隔离级别下是不一样的。

innodb具体实现的时候,使用了一种叫做readview的定西。

4.2 readview

readview称为读视图,是事务在进行快照读的时候产生的,算是一种数据结构。

readview中包含3个参数:

  • trx_list :系统活跃的(事务在执行,还没有提交)事务id列表;
  • up_limit_id :trx_list列表中最小的事务id;
  • low_limit_id :ReadView生成时刻系统尚未分配的下一个事务ID,也就是目前已出现过的事务ID的最大值+1;比如当前事务id已经分配到了4,那么low_limit_id的值就是5;

每个事务在进行自己的快照读时,都会产生自己事务对应的readview。

例如下图中:
在这里插入图片描述
有4个事务同时在执行,事务id分别为1,2,3,4;其中,1,2,3还没有提交,4已经提交,那么当事务2在进行快照读时,产生一个readview,其trx_list存的就是活跃的1,2,3,如下图:
在这里插入图片描述
此时,最小的事务id是1,最大的事务id是5 (尚未分配的下一个id),当前最新的事务id是4 (事务4的id)。

可见性算法
上图中右侧黄色部分就是本次查询到底该取哪个版本数据的规则,也叫可见性算法;

查找过程:
遍历undolog的最新数据到最老数据,逐个判断每条log的事务id,当作DB_TRX_ID,然后使用上图中黄色可见性算法比对,最终确定当前遍历的数据是不是目标数据。

读视图的产生时机
在不同的隔离级别下,readview产生的时机是不同的:

  • RC :每次进行快照读的时候,都会产生新的readview;
  • RR :只有在第一次进行快照读的时候,才会产生readview,之后的操作都会使用第一次生成的readview。如果此事务中间发生了update等当前读操作,也会生成新的readview。

在这里插入图片描述

  • 9
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mysql机制是用来处理并发访问数据库时的问题,特别是在使用InnoDB引擎支持事务的情况下。机制可以按照的粒度分为表级和行级。表级是对整张表进行加,实现简单,消耗的资源较少,加快速,不容易出现死。而行级则是对当前操作的行进行加定粒度更小,可以提高并发性,但加的代价较高。 MySQL的InnoDB存储引擎默认的事务隔离级别是RR(可重复读),这是通过行级和多版本并发控制(MVCC)一起实现的。在正常读取数据时,不会加,而在写入数据时才会进行加操作。 MVCC是通过一些技术实现的,包括隐藏字段、Read View和Undo log。隐藏字段用于存储数据版本信息,Read View用于控制事务的隔离级别,而Undo log则用于记录事务对数据的修改操作,以便在需要回滚时进行恢复。 总结起来,Mysql机制包括表级和行级,用于处理并发访问数据库时的问题。而MVCC则是InnoDB存储引擎实现事务隔离级别的一种机制,通过隐藏字段、Read View和Undo log来实现数据的一致性和并发控制。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Mysql机制+MVCC](https://blog.csdn.net/qq_45901741/article/details/120245265)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [MySQL和事务](https://download.csdn.net/download/weixin_38739919/13683140)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [mysql机制和mvcc](https://blog.csdn.net/u014618114/article/details/115534734)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值