MVCC 多版本并发控制协议
定义
MVCC(Multi-Version Concurrency Control):多版本并发控制
是一种并发控制机制,在数据库中用来控制并发执行的事务,控制事务隔离进行。
核心思想
MVCC是通过保存数据在某个时间点的快照来进行控制的。使用MVCC就是允许同一个数据记录拥有多个不同的版本。然后在查询时通过添加相应的约束条件,就可以获取用户想要的对应版本的数据。
基本数据结构
rede log:
重做日志记录。存储事务操作的最新数据记录。
undo log:
撤回日志记录,也称为版本链。当前事务未提交之前,undo log保存了当前事务的正在操作的数据记录的所有版本信息,undo log中数据可以作为数据旧版本快照提供其他并发事务进行快照读。每次有其他事务提交对当前数据行的修改,都是添加到undo log中。undo log是由每个数据行的多个不同的版本连接在一起构成一个记录“链表”。
read_view:
快照:会对数据在每个时刻的状态拍成照片记录下来。那么之后获取某时刻的数据时就还是原来的照片上的数据,不会改变。
MVCC在Mysql的实现
基本数据结构的定义:
在Mysql中,在实现MVCC时,会为每个表添加如下几个隐藏的字段;
DATA_TRX_ID:标记了最新更新这条行记录的transaction id,每处理一个事务,其值自动设置为当前事务ID(DATA_TRX_ID只有在事务提交之后才会更新)
DATA_ROLL_PTR:一个roolback指针,指向当前这一行数据的上一个版本,找之前版本的数据就是通过这个指针,通过这个指针将数据的多个版本来凝结在一起构成一个undo log版本链
DB_ROW_ID:隐含的自增ID,如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引。这是一个用来唯一标识每一行的字段
DELETE BIT位:用于标识当前是否被删除,这里的不是真正的删除数据,而是标志出来的删除。真正意义的删除是在commit的时候。
字段 | 位数 |
---|---|
DATA_TRX_ID | 6字节 |
DATA_ROOL_PTR | 7字节 |
DB_ROW_ID | 6字节 |
增删改查:
增加:INSERT
设置新记录的DATA_TRX_ID为当前事务ID,其他的采用默认的。
删除:DELETE
修改DATA_TRX_ID的值为当前执行删除操作事务的ID,然后设置DELETE BIT为True,表示被删除
修改:UPDATE <==> INSERT+DELETE
用X锁锁定该行
记录redo log:将更新之后的数据记录到redo log中以便日后使用
记录undo log:将更新之后的数据记录到undo log中的当前数据行更新前的数据行,同时设置更新之前的数据行的DATA_TRX_ID为当前事务ID,并且设置DELETE BIT为True,表示被删除。
查找:SELECT
如果当前数据行的DELETE BIT 为False,只查找版本早于当前版本的数据行(也就是数据行的DATA_TRX_ID必须小于等于当前事务的ID),这确保当前事务读取的行都是事务之前已经存在的 ,或者是有当前事务创建或修改的行
如果当前数据行的DELETE BIT为True,表示被删除,那么只能返回DATA_TRX_ID的值大于当前事务的行。获取在当前事务开始之前,还没有被删除的行。
使用MVCC核心优势
在Mysql中,使用MVCC本质上是为了在进行读操作的时候代替加锁,减少加锁带来的负担
在Mysql的InnoDB引擎,并且是在RR隔离级别下,通过使用MVCC和gap锁来解决幻读问题
行级锁 、表级锁、乐观锁 、悲观锁
悲观锁(加的是表级锁) 一方:查询语句加 for update;另一方:查询语句加 for
update;当进行更新语句的时候,另一方不能进行更新操作
乐观锁:更新语句设置版本号,在指定版本中更新数据
表级锁,where用的是非主键,一般指的共享锁,是不可对该表执行DDL操作,但DML操作都不限制。
行级锁,where用主键一般是id,一般指的是排它锁,即被锁定就不能更改、删除,只可以被其他会话select,行级锁之前需要加表结构共享锁。