深入了解MVCC数据库并发控制

深入了解MVCC数据库并发控制

问题:

image.png
image.png

我们知道这个是因为数据库的隔离级别,那到底是怎么实现的呢?
思考这个问题的同时我们先了解一下mvcc的一些定义

定义:

MVCC全称Mutli Version Concurreny Control,多版本并发控制,也可称之为一致性非锁定读;它通过行的多版本控制方式来读取当前执行时间数据库中的行数据。实质上使用的是快照数据,这样就可以实现不加锁读。MVCC 主要应用于 Read Commited 和 Repeatable read 两个事务隔离级别。

MVCC能解决什么问题,好处是?数据库并发场景有三种,分别为
读-读:不存在任何问题,也不需要并发控制
读-写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读
写-写:有线程安全问题,可能会存在更新丢失问题

MVCC带来的好处是?
多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。 所以MVCC可以为数据库解决以下问题
在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能 同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题

好的,现在进入正题

MVCC实现

MVCC 只是一种 乐观 的实现形式,它是通过 一种 可见性算法 来实现数据库并发控制
MVCC的实现依赖于 每行的隐藏字段,DB_TRX_ID,DB_ROLL_PTR,删除标记位,还有read_view

image.png

1 DB_TRX_ID 事务id占6 字节,表示这一行数据最后插入或修改的事务id。此外删除在内部也被当 作一次更新,在行的特殊位置添加一个删除标记(记录头信息有一个字节存储是否删除的标记)。2 DB_ROLL_PTR 回滚指针占7字节,回滚指针指向被写在Rollback segment中的undoLog记录,在该行数据被更新的时候,undoLog 会记录该行修改前内容到undoLog。
3 DB_ROW_ID 行ID占7字节,他就项自增主键一样随着插入新数据自增。如果表中不存主键 或者 唯一索引,那么数据库 就会采用DB_ROW_ID生成聚簇索引。否则DB_ROW_ID不会出现在索引中

其实还有一个删除的flag字段,用来判断该行记录是否已经被删除

MVCC 的两种读形式

在讲 MVCC 的实现原理之前,我觉很有必要先去了解一下 MVCC 的两种读形式。
快照读:读取的只是当前事务的可见版本,不用加锁。而你只要记住 简单的 select 操作就是快照读(select * from table where id = xxx)。
当前读:读取的是当前版本,比如 特殊的读操作,更新/插入/删除操作

而 MVCC 使用的是其中的** 事务字段,回滚指针字段,是否删除字段**。我们来看一下现在的表格

删除标志 事务Id 回滚指针 id name password
isDelete DB_TRX_ID DB_ROLL_PTR id name password
true/flase ax11122… ax11122… 1 小明 *****
那么如何通过这三个字段来实现 MVCC 的 呢?还差点东西! undoLog(回滚日志) 和 read-view(读视图)

undoLog: 事务的回滚日志,是 可见性算法 的非常重要的部分,分为两类。
insert undo log:事务在插入新记录产生的undo log,当事务提交之后可以直接丢弃
update undo log:事务在进行 update 或者 delete 的时候产生的 undo log,在快照读的时候还是需要的,
所以不能直接删除,只有当系统没有比这个log更早的read-view了的时候才能删除。ps:所以长事务会
产生很多老的视图导致undo log无法删除 大量占用存储空间。

read-view: 读视图,是MySQL秒级创建视图的必要条件,比如一个事务在进行 select 操作(快照读)的时候
会创建一个 read-view ,这个read-view 其实只是三个字段。
alive_trx_list:read-view生成时刻系统中正在活跃的事务id。
up_limit_id:记录上面的 alive_trx_list 中的最小事务id。
low_limit_id:read-view生成时刻,目前已出现的事务ID的最大值 + 1。

其实主要思路就是:当生成read-view的时候如何去拿获取的 DB_TRX_ID 去和 read-view 中的三个属性(上面讲了)去作比较。我来说一下三个步骤,如果不是很理解可以参考着我后面的实践结合着去理解。
首先比较这条记录的 DB_TRX_ID 是否是 小于 up_limit_id 或者 等于当前事务id。如果满足,那么说明当前事务能看到这条记录。如果大于则进入下一轮判断
然后判断这条记录的 DB_TRX_ID 是否 大于等于 low-limit-id。如果大于等于则说明此事务无法看见该条记录,不然就进入下一轮判断。
判断该条记录的 DB_TRX_ID 是否在活跃事务的数组中,如果在则说明这条记录还未提交对于当前操作的事务是不可见的,如果不在则说明已经提交,那么就是可见的。

如果此条记录对于该事务不可见且 ROLL_PTR 不为空那么就会指向回滚指针的地址,通过undolog来查找可见的记录版本。

流程图

image.png

回到前面的问题


image.png

首先事务A开启了事务(当然这不算开启,在RR模式下 真正获取read-view的是在进行第一次进行快照读的时候)。我们假设事务A的事务id为2,事务B的id为3。
然后事务A进行了更新操作,如图所示,更新操作创建了一个新的版本并且新版本的回滚指针指向了旧的版本(注意 undo log其实存放的是逻辑日志,这里为了方便我直接写成物理日志)。


image.png

首先,在进行快照读的时候我们会创建一个 read-view 这个时候我们的 read-view 是
up-limit-id = 2
alive-trx-list = [2,3]
low-limit-id = 4

然后我们获取那两个没有被修改的记录(没有顺序,这里为了一起解释方便)
我们获取到(2,小方)和(3,小张)这两条记录,发现他们两的 DB_TRX_ID = 1
我们先判断 DB_TRX_ID 是否小于 up-limit-id 或者等于当前事务id
发现 1<2 小于 up-limit-id ,则可见 直接返回视图。

然后我们获取更改了的数据行

其实你也发现了这是一个链表,此时链表头的 DB_TRX_ID 为 2
我们进行判断 2 < 2 不符合,进入下一步判断
判断 DB_TRX_ID >= low_limit_id 发现此时是 2 >= 4 不符合 故再进入下一步
此时判断 Db_TRX_ID 是否在 alive_trx_list 活跃事务列表中,发现这个 DB_TRX_ID 在活跃列表中,所以只能说明该行记录还未提交,不可见。
最终判断不可见之后通过回滚指针查看旧版本,发现此时 DB_TRX_ID 为1 故再次进行判断 DB_TRX_ID < up-limit-id ,此时 1 < 2 符合 ,所以可见并返回
所以最终返回的是


image.png

理解了上面的问题,现在我们可以思考下面两个问题:

思考1:

image.png

思考2:
可重复读(REPEATABLE READ): 可以避免“脏读”,“不可重复读”两个问题,会有“幻读”问题。 MySQL默认隔离级别,但是在MySQL中,此隔离级别解决了“幻读”问题

参考:
https://www.jianshu.com/p/8845ddca3b23
https://juejin.im/post/5e97d6b7e51d4546f5790f7e#heading-0
https://draveness.me/database-concurrency-control

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