写在前面:勿以事小而不为,用心做事,把它做好!
一. MVCC
-
什么是MVCC?
MVCC (Multiversion Concurrency Control),即多版本并发控制技术,它使得大部分支持行锁的事务引擎,不再单纯的使用行锁来进行数据库的并发控制,取而代之的是把数据库的行锁与行的多个版本结合起来,只需要很小的开销,就可以实现非锁定读,从而大大提高数据库系统的并发性能
简化理解:通过数据行的多版本来提升数据库系统的并发性能(一种优化的手段)
读锁:也叫共享锁、S锁
写锁:又称排他锁、X锁 -
多版本如何理解?
innodb引擎存储的行数据中包含一些额外的存储信息 DATA_TRX_ID,DATA_ROLL_PTR,DB_ROW_ID,DELETE BIT
a. 6字节的DATA_TRX_ID 标记了最新更新这条行记录的transaction id
b. 7字节的DATA_ROLL_PTR 指向当前记录项的rollback segment的undo log记录,找之前版本的数据就是通过这个指针
c. 6字节的DB_ROW_ID,当由innodb自动产生聚集索引时,聚集索引包括这个DB_ROW_ID的值,否则聚集索引中不包括这个值.,这个用于索引当中
d. DELETE BIT位用于标识该记录是否被删除,这里的不是真正的删除数据,而是标志出来的删除。真正意义的删除是在commit的时候 -
innodb引擎中,每个事务都存在一个唯一的transaction id . 它是事务在开启的时候向innodb事务系统申请的,并且按照申请顺序严格递增!
每次新开启一个事务,通常习惯将之隐喻为一个 '快照’ -
数据行存在多个版本,当某个事务更新一行数据的时候,会将该事务的transaction id 赋值给数据行的 DATA_TRX_ID,进而形成一个新的版本!
二. MVCC如何确保事务隔离的可重复读特性?
-
可重复读:一个事务在开启的时候可以看到所有已经提交的事务结果,但是在事务执行期间,其他事务更新对它不可见
-
在实现上,innodb为每个事务构建一个数组,用来保存这个事务启动瞬间,当前正在活跃的所有事务ID (活跃指的是启动了但还未提交)
数组里面ID最小值称之为 低水位,最大值加1称之为 高水位,视图数组和高水位组成了当前事务的一致性视图(read-view) -
一个数据版本,对于一个事务视图来说,除了自己的更新总是可见外,有三种情况:
a. 版本未提交,不可见
b. 版本已提交,但是是在视图创建后提交的,不可见
c. 版本已提交,并且是在视图创建前提交的,可见 -
什么是当前读?
a. update更新数据都是先读后写的,而这个读只能是读当前的值,称之为 ‘ 当前读 ’
b. 除了update外,select语句加锁也是当前读、
mysql> select k from t where id = 1 lock in share mode; (共享锁)
mysql> select k from t where id = 1 for update; (排它锁)
三. MVCC实例讲解可重复读
- 引出问题
mysql> create table t (
'id' int(11) not null,
'k' int(11) default null,
primary key ('id')
) engine = innodb;
insert into t(id,k) values(1,1),(1,2);
start transaction with consistent snapshot 表示马上开启一个事务,mysql 默认 autocommit = 1;
问题来了:事务A,B,C查询的结果分别为多少?
根据可重复读的隔离级别:事务A的查询结果为1,事务B的查询结果为3
- 解剖问题
我们做出如下假设:
a. 事务A开始前,系统只存在一个活跃事务ID 是99
b. 事务A,B,C的版本号分别为100,101,102,且当前系统只存在这4个事务
c. 三个事务开始前,数据(1,1)的DATA_TRX_ID 为 90
这样,根据上文我们可以得出事务A的视图组为 [99,100],B为 [99,100,101],C为 [99,100,101,102],将上图进行简化:
d.数据(1,1)最早版本为 (90,1,1)
e.事务C首先更新,版本变为 (102,1,2)
f. 事务B再次更新,版本变为 (101,1,3)
g.因此事务A [99,100]查询数据时候,由于101,102对它不可见,所以事务A查询结果为1,又由于uodate为当前读,所以事务B查询结果为3
上述多数内容借鉴学习有感于:
林晓斌老师mysql实战45讲
及
https://www.cnblogs.com/chenpingzhao/p/5065316.html