最近通过《高性能MySQL》一书学习MySQL方面的知识,在看到书中所讲InnoDB-MVCC部分的时候,有一种强烈的感觉,这不就是乐观锁吗(入门级小学徒的疑惑脸)?当下便去网上以各种方式查找阅读MVCC和乐观锁相关的博客,发现大部分的博客对于这两者之间的关系都只字不提,提了的也是众说纷纭,关于两者关系的细节方面也十分暧昧没有定论。在暂时无法得出最终结论的情况下,我先谈谈在学习这方面知识后我自己对两者的理解,然后试着得出自己的结论,正确与否大家一起思考。

在解释MVCC之前,我首先引用《高性能MySQL》书中原文来解释一下隔离级别:

READ UNCOMMITTED(未提交读):在READ UNCOMMITTED级别,事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,这也被称为脏读。

READ COMMITTED(提交读):大多数数据库默认的隔离级别(MySQL除外)。在READ COMMITTED级别,一个事务开始时,只能“看见”已经提交的事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的,这个级别有时候也叫做不可重复读,因为同一事务中两次执行同样的查询,可能会得到不一样的结果。

REPEATABLE READ(可重复读):这是MySQL默认的隔离级别,解决了脏读的问题。该级别保证了在同一事务中多次读取同样记录的结果是一致的。但是理论上,该隔离级别还是无法解决另外一个幻读的问题。所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行。

SERIALIZABLE(可串行化):该隔离级别下通过强制事务串行执行,避免了幻读的问题。简单来说,SERIALIZABLE会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。

上面解释隔离级别时提到了,在REPEATABLE READ隔离级别下,尽管解决了不可重复读,但还是存在幻读的问题。如果要避免幻读,就得在事务执行的时候加锁,但是大量的锁会严重影响性能。怎样才能不通过加锁还能解决幻读呢?这就是MVCC要做的事情。

MVCC是Multi-Version Concurrency Control(多版本并发控制)的缩写,很多数据库都实现了MVCC,但是在不同的存储引擎中MVCC的实现是不同的,今天所说的是InnoDB中的MVCC实现。InnoDB的MVCC,是通过在每行记录后保存两个隐藏的列来实现的(用户不可见)。一个列保存行创建的时间,一个列保存行过期(删除)的时间,这里所说的时间并不是传统意义上的时间,而是系统版本号,下面是REPEATABLE READ隔离级别下MVCC的具体操作:
-SELECT
InnoDB会根据以下两个条件检查每行记录:
(1)InnoDB只查找版本早于当前事务版本的数据行(行的系统版本号小于或者等于事务的系统版本号),这样可以确保事务读取到的行,要么是在事务开始之前已经存在的,要么是事务自身插入或者修改过的(结合以下INSERT、UPDATE操作理解)。
(2)行的删除版本要么未定义,要么大于当前事务版本号。可以确保事务读取到的行,在事务开启之前未被删除(结合以下DELETE操作理解)。
-INSERT
InnoDB为新插入的每一行保存当前系统版本号作为行版本号。
-DELETE
InnoDB为删除的每一行保存当前系统版本号作为行删除标识(第二个隐藏列的作用来了)。
-UPDATE
InnoDB将更新后的列作为新的行插入数据库(并不是覆盖),并保存当前系统版本号作为该行的行版本号,同时保存当前系统版本号到原来的行作为行删除标识。

到这里,MVCC是什么以及它做了什么事基本上已经说清楚了,为什么在学习了MVCC后我会产生“这就是乐观锁”的想法呢(实际上很多人都有这种想法,在一些博客里也有人说MVCC就是乐观锁)?有这几个原因。首先,InnoDB中MVCC和乐观锁(其实这么说是不严谨的,后面会解释为什么)都是通过“不加锁”的手段来实现加锁的效果。其次它们的不加锁手段都是通过版本号去控制的。通过这两点也不难看出为什么会有很多人在MVCC和乐观锁之间产生疑问。

那么乐观锁是怎么实现的呢?最常见的就是通过数据版本(Version)记录机制实现。数据版本和InnoDB-MVCC中的系统版本作用相似不做过多解释。通过为数据库表增加一个数字类型的字段作为版本标识Version(用户可见,字段名自定),当读取数据时,将其Version的值一同读出,数据每更新一次,Version都增加1,当提交更新的时候,判断数据库表对应行的当前版本信息与第一次读取出来的Version值进行对比,如果一致,则给与更新,否则不予更新(可以不涉及事务,但是MVCC机制必须依托于事务,事实上隔离级别本就是事务的隔离级别)。具体操作如下:

SELECT id, name, Version FROM testable;(例如id=1,Version=1024)
UPDATE testable SET name=’张三’,Version=Version+1 WHERE id=1 AND Version=1024;

从上面的所有文字中,我们还是无法得出一个有效的结论,只看得出InnoDB-MVCC和文中所提到的乐观锁确实很像,它们到底是何关系我们还是无从所知。那我们再来看看《高性能MySQL》中所提到的一句话:不同存储引擎的MVCC实现是不同的,典型的有乐观并发控制和悲观并发控制。看完这句话我们再结合上文,可以得出这样一个结论:MVCC并不是乐观锁,InnoDB所实现的MVCC才是乐观锁(当然也有其他存储引擎利用乐观并发控制的思想实现MVCC),更严谨一点来说,乐观锁并不是一种具体的技术,乐观锁只是一种并发控制的思想,所有认为“并发事务不算大”而采用非加锁的形式来实现“加锁”效果的控制机制我们都认为它是乐观锁。既然如此,那我们之前提到的乐观锁就不能叫乐观锁了,它只是乐观锁的一种表达方式,是一种在用户行为上通过非加锁的方式来实现并发控制的手段。同样的MVCC更不能称之为乐观锁,只能说InnoDB实现的MVCC是一种在系统行为上通过非加锁的方式来实现并发控制的手段。

总结来说,InnoDB-MVCC是一种系统行为,在REPEATABLE READ隔离级别下,它通过乐观并发控制解决了该隔离级别所不能解决的幻读,但是前提是这些都得依托于事务的封装。尽管如此,它还是无法完全解决一些并发业务场景下的问题,并且过多的事务使用会严重影响系统的性能,这就需要通过用户行为去约束(最开始所提到的乐观锁)。

所以,最后的结论就是,MVCC并非乐观锁,但是InnoDB存储引擎所实现的MVCC是乐观的,它和之前所提到的用户行为的“乐观锁”都采用的是乐观机制,属于不同的“乐观锁”手段,它们都是“乐观家族”的成员。

原文:https://blog.csdn.net/Jeaforea/article/details/82181449

知乎:

在数据库中,并发控制是指在多个用户/进程/线程同时对数据库进行操作时,如何保证事务的一致性和隔离性的,同时最大程度地并发。

当多个用户/进程/线程同时对数据库进行操作时,会出现3种冲突情形:

  1. 读-读,不存在任何问题
  2. 读-写,有隔离性问题,可能遇到脏读(会读到未提交的数据) ,幻影读等。
  3. 写-写,可能丢失更新

要解决冲突,一种办法是是锁,即基于锁的并发控制,比如2PL,这种方式开销比较高,而且无法避免死锁。

多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。 这样在读操作不用阻塞写操作,写操作不用阻塞读操作的同时,避免了脏读和不可重复读

乐观并发控制(OCC)是一种用来解决写-写冲突的无锁并发控制,认为事务间争用没有那么多,所以先进行修改,在提交事务前,检查一下事务开始后,有没有新提交改变,如果没有就提交,如果有就放弃并重试。乐观并发控制类似自选锁。乐观并发控制适用于低数据争用,写冲突比较少的环境。

多版本并发控制可以结合基于锁的并发控制来解决写-写冲突,即MVCC+2PL,也可以结合乐观并发控制来解决写-写冲突。

 
链接:https://www.zhihu.com/question/27876575/answer/71836010

InnoDB-MVCC与乐观锁的更多相关文章

  1. MySQL/InnoDB中,乐观锁、悲观锁、共享锁、排它锁、行锁、表锁、死锁概念的理解

    文章出处:https://www.souyunku.com/2018/07/30/mysql/?utm_source=tuicool&utm_medium=referral MySQL/Inn ...

  2. 【数据库】悲观锁与乐观锁与MySQL的MVCC实现简述

    悲观锁 悲观锁,就是一种悲观心态的锁,每次访问数据时都会锁定数据: 乐观锁 乐观锁,就是一种乐观心态的锁,每次访问数据时并不锁定数据,期待数据并没作修改,如果数据没被修改则作具体的业务 应用程序上使用 ...

  3. MYSQL中的乐观锁实现(MVCC)简析

    https://segmentfault.com/a/1190000009374567#articleHeader2 什么是MVCC MVCC即Multi-Version Concurrency Co ...

  4. 悲观锁,乐观锁以及MVCC

    在上文中,我们探讨了MySQL不同存储引擎中的各类锁,在这篇文章中我们将要讨论的是MySQL是如何实现并发控制的.并发问题有三种,分别为: 读-读,不存在任何问题 读-写,有隔离性问题,可能遇到脏读( ...

  5. innodb 悲观锁,乐观锁

    转 http://www.cnblogs.com/chenwenbiao/archive/2012/06/06/2537508.html CREATE TABLE `products` ( `id` ...

  6. 乐观锁和 MVCC 的区别?

    二者不是一个层面的东西. MVCC(Multi-Version Concurrent Control),基于快照隔离机制(Snapshot Isolations)进行多版本并发控制,是一种以乐观锁为理 ...

  7. InnoDB关于事务、锁、MVCC专题

    目录 并发所带来的的问题 脏写 脏读 不可重复读 幻读 事务 事务的特性 事务的四种隔离级别 锁 为什么要加锁 InnoDB的七种锁 不同事务RR和RC下加锁的规则 MVCC mvcc进一步提高并发 ...

  8. 通过版本号实现乐观锁(MVCC)

    乐观锁大多是基于数据版本记录的机制实现 , 如 , 为每一行数据增加一个整型版本标识(version) , 每次数据更新都把版本号+1 工作原理:读取出数据时,将此版本号一同读出,之后更新时,对此版本 ...

  9. 【mysql】关于乐观锁

    一.乐观锁介绍 乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检,乐观锁适用于 ...

随机推荐

  1. poi包冲突问题(excel)

    1. 所需jar包 涉及的poi (1)poi-3.14.jar  (HSSF) 依赖:commons-logging-1.2.jar.log4j-1.2.17.jar.commons-codec.1 ...

  2. virtualenvwrapper 虚拟环境的使用 和 python 安装源的更改

    virtualenvwrapper 虚拟环境的使用 鉴于virtualenv不便于对虚拟环境集中管理,所以推荐直接使用virtualenvwrapper. virtualenvwrapper提供了一系 ...

  3. 【Python 22】52周存钱挑战2.0(列表list和math函数)

    1.案例描述 按照52周存钱法,存钱人必须在一年52周内,每周递存10元.例如,第一周存10元,第二周存20元,第三周存30元,直到第52周存520元. 记录52周后能存多少钱?即10+20+30+. ...

  4. HBase源码实战:BufferedMutator

    /** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agr ...

  5. 并发框架Disruptor场景应用

    今天用一个停车场问题来加深对Disruptor的理解.一个有关汽车进入停车场的问题.当汽车进入停车场时,系统首先会记录汽车信息.同时也会发送消息到其他系统处理相关业务,最后发送短信通知车主收费开始.看 ...

  6. Offset Management For Apache Kafka With Apache Spark Streaming

    An ingest pattern that we commonly see being adopted at Cloudera customers is Apache Spark Streaming ...

  7. JavaScript 函数闭包的应用

    一.模仿块级作用域 JavaScript 没有块级作用域的概念,那么可以模拟像java中将很多变量私有化封装起来,保护数据,防止数据泄漏,封装细节,这样安全性和可控性更高 function box(c ...

  8. mysql 有没有参数都报错“mysql: unknown option”

    报错: [root@XXXX tmp]# mysql -uroot -pmysql: unknown option '--You have new mail in /var/spool/mail/ro ...

  9. .Net Core应用框架Util介绍(三)

    上篇介绍了Util的开发环境,并让你把Demo运行起来.本文将介绍该Demo的前端Angular运行机制以及目录结构. 目录结构 在VS上打开Util Demo,会看见如下的目录结构. 现代前端通常采 ...

  10. oracle实例安装到 4% 不能继续安装

    较为悲催的问题, 一直不知道如何解决: 偶尔听到群里的大神提起: 今天特地拿出来分享一下: 希望大家碰到能早点解决 是CPU问题: 将cpu 核心数 改为 2的指数倍: 或者将cpu打上补丁就好了: ...