MySQL-InnoDB-MVCC多版本并发控制

(Multiversion Concurrency Control)

1.什么是MVCC

多版本并发控制: 指的是一种提高并发的技术。最早的数据库系统,只有读读之间可以并发,读写,写读,写写都要阻塞。引入多版本之后,只有写写之间相互阻塞,其他三种操作都可以并行,这样大幅度提高了InnoDB的并发度。在内部实现中,与Postgres在数据行上实现多版本不同,InnoDB是在undolog中实现的,通过undolog可以找回数据的历史版本。找回的数据历史版本可以提供给用户读(按照隔离级别的定义,有些读请求只能看到比较老的数据版本),也可以在回滚的时候覆盖数据页上的数据。在InnoDB内部中,会记录一个全局的活跃读写事务数组,其主要用来判断事务的可见性。 版本链

2. 为什么需要MVCC

MVCC主要是为了提高并发的读写性能,不用加锁就能让多个事务并发读写。比单纯的加锁更高效。

a. MySQL大多数实现都不是简单的行级锁。基于提升并发性能,一般采用MVCC,

b. 可以认为MVCC是行级锁的一个变种,典型的有乐观并发控制,悲观并发控制

c. MVCC 只在RC 和 RR级别下工作。因为 READ UNCOMMITTED 总是读取最新的数据行, 而不是符合当前事务版本的数据行。而 SERIALIZABLE 则会对所有读取的行都加锁。

3.重要概念

3.1 read view(一致性视图),快照snapshot

事务快照是用来存储数据库的事务运行情况。一个事务快照的创建过程可以概括为:

查看当前所有的未提交并活跃的事务,存储在数组中

选取未提交并活跃的事务中最小的XID,记录在快照的xmin中

选取所有已提交事务中最大的XID,加1后记录在xmax中

read view 主要是用来做可见性判断的

3.2 read view在RC, RR下生成时机不同,可见性不同:

    3.2.1 在InnoDB(默认RR下),事务在begin/start transaction之后第一条select读操作后,生成一个快照(read view)

    3.2.2 在InnoDB(RC下),事务在每一个select之后,生成一个快照(read view)

3.3 undo log

3.4 InnoDB存储引擎在数据库每行数据后面添加三个字段

事务ID(DB_TRX_ID) :6字节: 用来标识最近一次对本行记录做修改(insert|update)的事务的标识符, 即最后一次修改(insert|update)本行记录的事务id。

至于delete操作,在innodb看来也不过是一次update操作,每条记录的头信息( record header )里都有一个专门的  bit ( deleted_flag )来表示当前记录是否已经被删除。

回滚指针(DB_ROLL_PTR): 7字节,指写入回滚段(rollback segment)的 undo log record (撤销日志记录记录)。

如果一行记录被更新, 则 undo log record 包含 '重建该行记录被更新之前内容' 所必须的信息。

隐藏主键列(DB_ROW_ID):6字节 包含一个随着新行插入而单调递增的行ID, 当由innodb自动产生聚集索引时,聚集索引会包括这个行ID的值,否则这个行ID不会出现在任何索引中。


当执行查询sql时,会生成一致性视图 read-view,它由执行查询时所有未提交事务id数组()和已创建最大事务id(max_id)组成。查询的数据结果需要跟read-view做对比从而得到快照结果

版本链比对规则:

1. 绿色(trx_id < min_id) , 表示这个版本是已提交的事务生成的,这个数据是可见的

2. 红色(trx_id > max_id) , 这个版本是由将来启动的事务生成的,肯定是不可见的。

3. 粉色(min_id<= trx_id <=max_id),两种:

    a. 若row的trx_id 在数组中,表示这个版本由未提交的事务生成的,不可见,当前自己的事务是可见的。

    b. 若row的trx_id 不在数组中,表示这个版本是已提交事务生成的,可见。

删除是 update的特殊情况,会将版本链最新的数据复制一份,将trx_id修改成删除操作事务的trx_id,在头信息(record header)里的(deleted_flag)标记bit上写上true,表示当前记录被删除,查询时按照以上规则如果deleted_flag为true,则不返回数据


当前读和快照读

1.MySQL的InnoDB存储引擎默认事务隔离级别是RR(可重复读), 是通过 "行排他锁+MVCC" 一起实现的, 不仅可以保证可重复读, 还可以部分防止幻读, 而非完全防止;

2.为什么是部分防止幻读, 而不是完全防止?

效果: 在如果事务B在事务A执行中, insert了一条数据并提交, 事务A再次查询, 虽然读取的是undo中的旧版本数据(防止了部分幻读), 但是事务A中执行update或者delete都是可以成功的!!

因为在innodb中的操作可以分为当前读(current read)和快照读(snapshot read):

3.快照读(snapshot read)

简单的select操作(当然不包括select...lockinsharemode,select...forupdate)

4.当前读(current read) 官网文档 Locking Reads

select ... lock in share mode

select ... for update

insert

update

delete

在RR级别下,快照读是通过MVVC(多版本控制)和undo log来实现的,

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

innodb在快照读的情况下并没有真正的避免幻读, 但是在当前读的情况下避免了不可重复读和幻读!!!

小结

一般我们认为MVCC有下面几个特点:

每行数据都存在一个版本,每次数据更新时都更新该版本

修改时Copy出当前版本, 然后随意修改,各个事务之间无干扰

保存时比较版本号,如果成功(commit),则覆盖原记录, 失败则放弃copy(rollback)

就是每行都有版本号,保存时根据版本号决定是否成功,听起来含有乐观锁的味道, 因为这看起来正是,在提交的时候才能知道到底能否提交成功

而InnoDB实现MVCC的方式是:

事务以排他锁的形式修改原始数据

把修改前的数据存放于undo log,通过回滚指针与主数据关联

修改成功(commit)啥都不做,失败则恢复undo log中的数据(rollback)

二者最本质的区别是: 当修改数据时是否要排他锁定,如果锁定了还算不算是MVCC?

Innodb的实现真算不上MVCC, 因为并没有实现核心的多版本共存, undo log 中的内容只是串行化的结果, 记录了多个事务的过程, 不属于多版本共存。但理想的MVCC是难以实现的, 当事务仅修改一行记录使用理想的MVCC模式是没有问题的, 可以通过比较版本号进行回滚, 但当事务影响到多行数据时, 理想的MVCC就无能为力了。

比如, 如果事务A执行理想的MVCC, 修改Row1成功, 而修改Row2失败, 此时需要回滚Row1, 但因为Row1没有被锁定, 其数据可能又被事务B所修改, 如果此时回滚Row1的内容,则会破坏事务B的修改结果,导致事务B违反ACID。 这也正是所谓的 第一类更新丢失 的情况。

也正是因为InnoDB使用的MVCC中结合了排他锁, 不是纯的MVCC, 所以第一类更新丢失是不会出现了, 一般说更新丢失都是指第二类丢失更新。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349