MySQL-MVCC

1.什么是MVCC

MVCC:全称Multi-Version Concurrency Control,即多版本并发控制。MVCC是为MySQL并发场景下无锁生成读视图进行读操作来进行多版本控制。

或者叫

MVCC:一致性非锁定读

mvcc是基于MySQL的回滚机制,在并发场景下为读操作做的的读取的一个优化。

MVCC实现

实现基于undo log 版本链 + ReadView机制

https://www.51cto.com/article/641019.html

undolog

undo log存在的意义是确保数据库事务的原子性。

redolog

redo log用于保证事务的持久性,即ACID中的D。
redo log的主要功能是用于数据库崩溃时的数据恢复。

redo log保证事务的持久性,undo log用来帮助事务回滚及MVCC的功能。
数据持久化性能,批量插入,commit刷盘

Mysql 里会接触到三个核心日志分别是 binlog 、redo log、undo log, 这里面binlog是server层的日志,而redo log 和undo log都是引擎层(innodb)的日志,要换其他数据引擎那么就未必有redo log和undo log了。
https://zhuanlan.zhihu.com/p/213770128

2.不同隔离级别下MVCC

四种:
不同的隔离级别下,mvcc表现不同

  1. 读未提交 read-uncommitted
    • 还没提交的数据就能读到,不需要MVCC
  2. 读已提交read-committed
    • 例子:
      三个线程A,B,C
      A,B位修改线程,C线程为读线程。
      同一时刻,AC同时发起事务,A线程发起修改,C线程读取→此时C准备sleep,C已经开启事务,此时A去修改了,修改之前A首先会生成一版修改前快照(undolog)
      →A修改完提交,此时A有两个版本(修改前修改后)→此时B线程写,比也会生成快照,B修改完成提交,现在有3个版本了(A线程之前的版本,A线程修改后B线程修改前的版本,B线程修改后的版本)→C线程醒了,C访问那条数据?读取的是B线程提交的版本(最新提交数据)

此时事务不是隔离的(ACID的I)A,B事务影响C事务

  1. 可重复读repeatable-read:默认

    • 例子:
      三个线程A,B,C
      A,B位修改线程,C线程为读线程。
      同一时刻,AC同时发起事务,A线程发起修改,C线程读取→此时C准备sleep,C已经开启事务,此时A去修改了,修改之前A首先会生成一版修改前快照(undolog)
      →A修改完提交,此时A有两个版本(修改前修改后)→此时B线程写,比也会生成快照,B修改完成提交,现在有3个版本了(A线程之前的版本,A线程修改后B线程修改前的版本,B线程修改后的版本)→C线程醒了,C访问那条数据?读取的最原始的数据,即A修改前的数据
  2. 串行serializable

    • 也不需要MVCC,串行的

3.不同隔离级别下MySQL出现的问题及如何解决

3.1不同隔离级别下表现

  1. 读未提交 read-uncommitted

    • 读到未提交,发生脏读
      现在几乎看不到MySQL脏读,除非把事务隔离级别设为 read-uncommitted
  2. 读已提交 read-committed

    • 会发生幻读不可重复读
    • 幻读不可重复读两者却别不大,
      不可重复读:读取同一条数据,结果不一样
      幻读:读取数据的数据量不一样
      例子:同个事务里多次读,其他事务提交,结果不一样,不可重复读。
      例子:同个事务里多次读,其他事务删除数据提交,少了一条数据,幻读。
  3. 串行serializable,出现的问题就是慢

3.2 Mysql锁如何解决问题

可重复读级别,下next-key-lock机制

InnoDB存储引擎实现了如下两种标准的行级锁:

  1. 共享锁(S Lock),允许事务读一行数据。

  2. 排他锁(X Lock),允许事务删除或更新一行数据。

如果一个事务T1已经获得了行r的共享锁,那么另外的事务T2可以立即获得行r的共享锁,因为读取并没有改变行r的数据,称这种情况为锁兼容(Lock Compatible)。但若有其他的事务T3想获得行r的排他锁,则其必须等待事务T1、T2释放行r上的共享锁——这种情况称为锁不兼容
在这里插入图片描述

MySQL锁分3种
InnoDB存储引擎有3种行锁的算法

  1. Record Lock:单个行记录上的锁

  2. Gap Lock:间隙锁,锁定一个范围,但不包含记录本身

  3. Next-Key Lock∶Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身

Record Lock总是会去锁住索引记录,如果InnoDB存储引擎表在建立的时候没有设置任何一个索引,那么这时InnoDB存储引擎会使用隐式的主键来进行锁定。

Next-Key Lock是结合了Gap Lock和Record Lock的一种锁定算法,在Next-Key Lock算法下,InnoDB对于行的查询都是采用这种锁定算法。

在InnoDB 默认的事务隔离级别下,即REPEATABLE READ下,InnoDB存储引擎采用Next-Key Locking这种锁定算法。例如一个索引有10,11,13和20这四个值,那么该索引可能被Next-Key Locking的区间为:

(-∞,10]

(10,11]

(11,13]

(13,20]

(20,+∞)

![在这里插入图片描述](https://img-blog.csdnimg.cn/e8569

当查询的索引含有唯一属性时,InnoDB存储引擎会对Next-Key Lock进行优化,将其降级为Record Lock,即仅锁住索引本身,而不是范围。

什么是唯一属性,其实就是我们所说的能够标识该行数据唯一的标识。

unique 字段。比如:主键就是唯一的,不重复的。我们也可以自己设计多个字段组合不重复,唯一的。

表t共有1、2、5三个值。在上面的例子中,在会话A中首先对a=5进行X锁定。而由于a是主键且唯一,因此锁定的仅是5这个值,而不是(2,5)这个范围,这样在会话B中插入值4而不会阻塞,可以立即插入并返回。即锁定由Next-Key Lock算法降级为了Record Lock,从而提高应用的并发性。

在这里插入图片描述

在这里插入图片描述

表z的列b是辅助索引,若在会话A中执行下面的SQL语句:

SELECT*FROM z WHERE b=3 FOR UPDATE

很明显,这时SQL语句通过索引列b进行查询,该列不是唯一属性,因此其使用传统的Next-Key Locking技术加锁,并且由于有两个索引,其需要分别进行锁定。对于聚集索引(primay-key a),其仅对列a等于5的索引加上Record Lock。而对于辅助索引b,其加上的是Next-Key Lock,锁定的范围是(1,3)。特别需要注意的是,InnoDB存储引擎还会对辅助索引下一个键值加上gap lock,即还有一个辅助索引范围为(3,6)的锁。

因此,若在新会话B中运行下面的SQL语句,都会被阻塞:

在这里插入图片描述

第一个SQL语句不能执行,因为在会话A中执行的SQL语句已经对聚集索引中列a=5的值加上X锁,因此执行会被阻塞。第二个SQL语句,主键插入4,没有问题,但是插入的辅助索引值2在锁定的范围(1,3)中,因此执行同样会被阻塞。第三个SQL语句,插入的主键6没有被锁定,5也不在范围(1,3)之间。但插入的值5在另一个锁定的范围(3,6)中,故同样需要等待。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值