“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 3 天,点击查看活动详情”
MVCC(多版本并发控制或者一致性非锁定读)指InnoDB存储引擎通过行多版本控制的方式来读取当前执行时间数据库中行的数据。如果读取的行正在执行DELETE或UPDATE操作,这时读取操作不会因此去等待行上锁的释放。相反地,InnoDB存储引擎会去读取行的一个快照数据。
在场景中: 一个线程开启进行修改某一行数据,对于行来说,上X锁,对于表来说,上IX锁 一个线程开启读同一行数据,对表来说上IS锁(IS和IX不冲突),对行来说因为有X锁所以会被阻塞,不能上S锁
由上述得到,因为阻塞导致并发降低,现在需要减少并发阻塞,所以出现了一致性非锁定读
MVCC关键部分:每一行记录的隐藏字段:事务版本号,row_id,roll_pointer(指针指向回滚段的日志)
当前读和快照读
快照读读取的是数据的可见版本,不加锁,比如默认不加锁的select语句
(快照数据其实就是当前行数据之前的历史版本, 每行记录可能有多个版本。)
select 语句加锁,update语句是当前读
Read View(一致性视图)
数据表中的一行记录,其实可能有多个版本(row),每个版本有自己的row trx_id
按照可重复读的定义,一个事务启动的时候,能够看到所有已经提交的事务结果。
但是之后,这个事务执行期间,其他事务的更新对它不可见(一个事务只需要在启动的时候声明说,“以我启动的时刻为准,如果一个数据版本是在我 启动之前生成的,就认;如果是我启动以后才生成的,我就不认,我必须要找到它的上一个版本”)
InnoDB为每个事务开辟一个数组,保存事务启动瞬间所有启动了但还没提交的事务ID(当前自己的事务就是还没提交)
数组里面事务ID的最小值记为低水位,当前系统里面已经创建过的事务ID的最大值加1记为高水位。
由此组成Read View
有以下匹配规则:
- 一个数据版本的row trx_id落在绿色区域上,那就是可见
- 落在红色就是不可见
- 落在黄色分类讨论,这个数组中存在当前row trx_id,就说明还没提交,肯定不可见
- 不存在当前row trx_id,表示已经提交了,可见
是别的数据的事务版本号来到当前事务的read view中进行匹配!!
可重复读的核心就是一致性读(consistent read);而事务更新数据的时候,只能用当前读。如 果当前的记录的行锁被其他事务占用的话,就需要进入锁等待
RC和RR的区别:
在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图
在读提交隔离级别下,每一个语句执行前都会重新算出一个新的视图。它总是读取行的最新版本,如果行被锁定了,则读取该行版本的最新一个快照。(从数据库理论的角度来看,其违反了事务ACID中的I的特性,即隔离性。)
PS: MVCC原理详解
《MySQL45讲》