Mysql中的MVCC机制

MVCC(Multi-Version Concurrency Control),多版本并发控制。

MVCC是一种并发控制的方法,通过维护数据多个版本的记录,以无锁的方式解决并发读写冲突。目的就是规避在读写冲突的时候进行加锁的操作。Mysql的Innodb引擎就使用了MVCC。

相关概念

要了解MVCC的实现机制,需要先知道Mysql中以下几个概念。

事物ID和DB_TRX_ID

事物ID

我们都知道innodb是支持事物的,在innodb中每一个事物创建时都会分配一个自增的ID作为事物为唯一标志,也就是事物ID。

DB_TRX_ID

数据表里每一行数据都会有一个隐藏字段DB_TRX_ID,用来存储创建或者最后一次修改此记录的事物ID

undo log和DB_ROLL_PTR

DB_ROLL_PTR

数据表里另外一个隐藏字段,DB_ROLL_PTR回滚指针,指向这条记录的上一个版本在undo log中的数据。

undo log

undo log存储每行记录的修改历史。可以简单理解undo log是一个与数据表结构相同的另外一张表,数据表的数据行字段它都有,数据表的行记录每修改一次,就将这行数据的当前记录写到undo log中,并将返回的undo log指针地址写入DB_ROLL_PTR,然后修改数据行数据、更新事物ID。

undo log主要分为两种:

insert undo log
代表事务在insert新记录时产生的undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃
update undo log
事务在进行update或delete时产生的undo log; 不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除

结构大概如下图所示:

图片来源:https://www.jianshu.com/p/8845ddca3b23

undo log可以作为mvcc中查找对应可读记录,也可以作为当前事物的rollback依据。
undo log也并不是无限增长的,会有另外一个线程会尝试清除早期的undo log记录,因为他们已经没有用处了。

当前读与快照读

当前读

当前读指的是读取数据当前最新数据。update、insert、delete、select for update(排他锁)、select lock in share mode。读取数据需要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。

快照读

快照读指的是在读取数据时,生成读取快照,在同一个事物中可能会一直读取此快照的数据。快照读读到的数据可能不是最新的,可能是历史版本的数据,这些历史版本的数据就是从undo log中获取的。
事物中的select 不加锁的情况会执行快照读,快照读依赖readview来实现。
快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读。

ReadView

读视图,由当前活跃事物ID的列表trx_list、当前活跃最小事物ID low_limit_id、下一个即将分配的事物ID up_limit_id,三个部分组成。

事物间可见性分析

基于ReadView的可见性分析逻辑

执行快照读的时候,会创建一个ReadView。定义被读取行的DB_TRX_ID 为trx_id。

  1. 比较 trx_id是否小于low_limit_id 或者为当前事物ID,如果为true,则代表修改此行数据的事物早已提交或者就是当前事务进行的修改,当前记录可见。否则进入下一步判断。
  2. 比较trx_id是否大于等于up_limit_id,如果为true,则代表修改此行记录的事物晚于当前读视图创建,当前记录不可见,根据DB_ROLL_PTR undo log指针找到上一条记录,从新进行可见性分析。否则进入下一步判断
  3. 判断trx_id是否在trx_list列表中,如果在,代表修改此行记录的事物还未提交,当前事务不可以读取当前记录,根据DB_ROLL_PTR undo log指针找到上一条记录,从新进行可见性分析。否则说明数据在readview生成的时候已经提交,当期事物可以读取当前记录。

数据库事物隔离级别与MVCC

  • 脏读
    读到了别的事物未提交的数据,由于别的事物有可能会回滚,相当于读到了错误的数据。
  • 不可重复读
    读到了别的事物已提交的数据,在当前事务中,前后两次的读取可能数据不一致。
  • 幻读
    也是读到了别的事物已提交的数据,在当前事务中,前后两次的读取可能数据不一致。与不重复读区别是,幻读指的是insert或delete产生的不一致,而不可重读指的是update产生的不一致。

数据库为了解决脏读、不可重复读、幻读,定义了事物间的隔离级别。

事物隔离级别
  • 串行化Serializable
    一切指令同步执行,也就没有以上的问题了。可以解决脏读、幻读、不可重读。
  • 可重复读Repeat Read、RR
    在同一事物中读取被修改的记录,总是一致的。可以解决脏读、不可重复读。
  • 读已提交Read Committed、RC
    可以读取别的事物已经提交的数据。可以解决脏读。
  • 读未提交Read UnCommitted
    可以读到别的事物未提交的数据。啥问题都没解决。

隔离级别是约严格需要的约束越多,相对的性能就会越差。
Mysql Innodb的默认数据库隔离级别为RR。
Oracle的隔离级别只支持Serializable和RC,另外提供了一种只读的模式,只允许select。

事物隔离级别与MVCC

在RR级别下,事物进行快照读时会检查当前事物是否已经创建过ReadView,如果存在,则使用已经创建的,这也是实现可重复的方法。
在RC级别下,事物每一次快照读都会创建一个新的ReadView,这样就会造成不可重复的和幻读的问题。

Innodb利用MVCC解决了RR级别下快照读中的幻读问题,当前读中的幻读问题需要使用GAP lock解决,也就是间隙锁。
举个例子:

创建user表,自增主键ID、name、age,三个字段;
插入两条数据1-张三-10、2-李四-20;

image.png

启动事物1,查询name=张三的记录,会返回1-张三;
启动事物2,新增记录3-张三-30;
在事物1中再次查询name=张三的记录,仍然返回1-张三;
在事物1中修改name=张三的age=45,提交;会发现1、3的age都会变为45。

image.png

这就是解决了快照读的幻读,而修改操作属于当前读,仍然有幻读的问题。
但是如果这里将事物2的提交事务延迟到事物1修改数据之后,会发现事物1的修改数据会被卡住。

这里就使用了间隙锁进行防止写的幻读。

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

推荐阅读更多精彩内容