MySQL事务 - MVCC

1、当前读和快照读


  • 快照读:读取的是记录的可见版本 (有可能是历史版本),不用加锁简单纯粹的查询操作,属于快照读
    SELECT * FROM student WHERE id=1;
    
  • 当前读:读取的是记录的最新版本,并且当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。特殊的查询操作、插入、更新、删除操作,属于当前读
    SELECT * FROM student WHERE id=1 LOCK IN SHARE MODE; //共享锁(S)
    SELECT * FROM student WHERE id=1 FOR UPDATE; //排他锁(X)
    INSERT INTO student VALUES (1, '张三'); //排他锁(X)
    UPDATE student SET name='李四' WHERE id=1; //排他锁(X)
    DELETE FROM student WHERE id=1; //排他锁(X)
    
    所有以上的语句,都属于当前读,读取记录的最新版本。并且,读取之后,还需要保证其他并发事务不能修改当前记录,对读取记录加锁。

为什么将插入、更新、删除操作,都归为当前读? 可以看看下面这个更新操作,在数据库中的执行流程:

UPDATE student SET name='李四' WHERE id=1;

在这里插入图片描述
从图中,可以看到一个Update操作的具体流程:

  1. 当Update SQL被发给MySQL后,MySQL Server会根据where条件,读取第一条满足条件的记录,然后InnoDB引擎会将第一条记录返回,并加锁 (current read)。
  2. 待MySQL Server收到这条加锁的记录之后,会再发起一个Update请求,更新这条记录。
  3. 一条记录操作完成,再读取下一条记录,直至没有满足条件的记录为止。

因此,Update操作内部,就包含了一个当前读。同理,Delete操作也一样。Insert操作会稍微有些不同,Insert可能会触发Unique Key的冲突检查,也会进行一个当前读。

根据上图的交互,针对一条当前读的SQL语句,InnoDB与MySQL Server的交互,是一条一条进行的,因此,加锁也是一条一条进行的:先对一条满足条件的记录加锁,返回给MySQL Server,做一些DML操作;然后在读取下一条加锁,直至读取完毕。

2、一致性非锁定读(consistent nonlocking read)


一致性非锁定读是指InnoDB存储引擎通过多版本控制(MVCC)读取当前数据库中行数据的方式。如果读取的行正在执行DELETE或UPDATE操作,这时读取操作不会因此去等待行上锁的释放。相反地,InnoDB会去读取行的一个快照。

在这里插入图片描述
上图直观地展现了InnoDB一致性非锁定读的机制。之所以称其为非锁定读,是因为不需要等待行上排他锁的释放。快照数据是指该行的之前版本的数据,每行记录可能有多个版本,一般称这种技术为行多版本技术。由此带来的并发控制,称之为多版本并发控制(Multi Version Concurrency Control / MVCC)。InnoDB是通过undo log来实现MVCC。

在事务隔离级别RC和RR下,InnoDB默认使用一致性非锁定读。然而,对于快照数据的定义却不同:

  • 在RC下,一致性非锁定读总是读取被锁定行的最新一份快照数据。
  • 在RR下,读取事务开始时的行数据版本。

举个栗子:

在这里插入图片描述
在会话B的事务中,将student表中id为1的记录修改为id=3,但是事务同样也没有提交,这样id=1的行其实加了一个排他锁。由于InnoDB在READ COMMITTED和REPEATABLE READ事务隔离级别下使用一致性非锁定读,这时如果会话A再次读取id为1的记录,仍然能够读取到相同的数据。此时,RC和RR事务隔离级别没有任何区别。

在这里插入图片描述
如上图所示,当会话B提交事务后,会话A再次运行SELECT * FROM student WHERE id=1;的SQL语句时,两个事务隔离级别下得到的结果就不一样了:

  • 对于RC事务隔离级别,它总是读取行的最新版本,如果行被锁定了,则读取该行版本的最新一个快照。因为会话B的事务已经提交,所以在该隔离级别下上述SQL语句的结果集是空的。
  • 对于RR事务隔离级别,总是读取事务开始时的行数据,因此,在该隔离级别下,上述SQL语句仍然会获得相同的数据。

3、InnoDB的MVCC实现


我们首先来看一下wiki上对MVCC的定义:

Multiversion concurrency control (MCC or MVCC), is a concurrency control method commonly used by database management systems to provide concurrent access to the database and in programming languages to implement transactional memory.
翻译:多版本并发控制(MCC 或 MVCC)是数据库管理系统常用的一种并发控制方法,用于提供对数据库的并发访问,并在编程语言中实现事务性内存。

由定义可知,MVCC是用于数据库提供并发访问控制的并发控制技术。与MVCC相对的,是基于锁的并发控制,Lock-Based Concurrency Control。

MVCC最大的好处就是:读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,因为它极大的增加了系统的并发性能,这也是为什么现阶段,几乎所有的RDBMS,都支持了MVCC。

多版本并发控制仅仅是一种技术概念,并没有统一的实现标准, 其核心理念就是数据快照。不同的事务访问不同版本的数据快照,从而实现不同的事务隔离级别。虽然字面上是说具有多个版本的数据快照,但这并不意味着数据库必须拷贝数据,保存多份数据文件,这样会浪费大量的存储空间。InnoDB通过事务的undo日志巧妙地实现了多版本的数据快照。数据库的事务有时需要进行回滚操作,这时就需要对之前的操作进行undo。因此,在对数据进行修改时,InnoDB会产生undo log。当事务需要进行回滚时,InnoDB可以利用这些undo log将数据回滚到修改之前的样子。

从上边的描述中我们可以看出来,所谓的MVCC指的就是在使用RC、RR这两种隔离级别的事务在执行普通的SEELCT操作时访问记录的版本链的过程,这样子可以使不同事务的“读-写”、“写-读”操作并发执行,从而提升系统性能。

RC、RR两个隔离级别的一个很大不同就是生成ReadView的时机不同,RC在每一次进行普通 SELECT 操作前都会生成一个ReadView,而RR只在第一次进行普通SELECT操作前生成一个ReadView,之后的查询操作都重复这个ReadView就好了。此处可参考《MySQL事务 - ReadView》

总结:MVCC是一种思想,MySQL使用undolog和ReadView可见性判断去实现了MVCC。 MVCC的最大好处就是读不加锁,读写不冲突,同时还能保证事务的隔离性。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值