数据库InnoDB-MVCC-多版本并发控制
-
- MVCC
-
- 当前读与快照读
- 三个隐式字段
- Undo log与undo log版本链
-
- undo log
- 版本链
- Readview
MVCC MVCC 称 Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段、undolog日志、readView。
当前读与快照读
当前读读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。
快照读:简单的
select
(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。Read Committed
:每次select,都生成一个快照读。Repeatable Read
:开启事务后第一个select语句才是快照读的地方。Serializable
:快照读会退化为当前读。
当我们创建一张表的时候,表中除了会又创建时添加的字段外,
InnoDB
还会自动的给我们添加三个隐藏字段及其含义分别是:隐藏字段 | 含义 |
---|---|
DB_TRX_ID | 最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID。 |
DB_ROLL_PTR | 回滚指针,指向这条记录的上一个版本,用于配合undolog,指向上一个版本。 |
DB_ROW_ID | 隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。 |
DB_ROW_ID
,得看当前表有没有主键,如果有主键,则不会添加该隐藏字段。Undo log与undo log版本链
undo log 回滚日志,在
insert
、update
、delete
的时候产生的便于数据回滚的日志。当insert
的时候,产生的undo log
日志只在回滚时需要,在事务提交后,可被立即删除。而update
、delete
的时候,产生的undo log
日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。版本链 有一张原始的数据表为
id | age | name | DB_TRX_ID | DB_ROLL_PTR |
---|---|---|---|---|
2 | 30 | A30 | 1 | null |
DB_TRX_ID
:代表最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID,是自增的。
DB_ROLL_PTR
:由于这条数据是才插入的,没有被更新过,所以该字段值为null。有四个并发事务同时访问这张表:
![MySql|数据库InnoDB-MVCC-多版本并发控制](http://img.readke.com/220724/134I21626-0.jpg)
文章图片
当执行完事务1,2,3中的对同一个数据的更改操作后,undo log会形成undo log版本链,记录数据变更之前的样子; 然后更新记录,并且记录本次操作的事务ID,回滚指针,回滚指针用来指定如果发生回滚,回滚到哪一个版本。
不同事务或相同事务对同一条记录进行修改,会导致该记录的undo log生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。
![MySql|数据库InnoDB-MVCC-多版本并发控制](http://img.readke.com/220724/134I26004-1.jpg)
文章图片
Readview
ReadView
(读视图)是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。ReadView
中包含了四个核心字段:字段 | 含义 |
---|---|
m_ids | 当前活跃的事务ID集合 |
min_trx_id | 最小活跃事务ID |
max_trx_id | 预分配事务ID,当前最大事务ID+1(因为事务ID是自增的) |
creator_trx_id | ReadView创建者的事务ID |
trx_id
代表当前undolog版本链对应事务ID。条件 | 是否可以访问 | 说明 |
---|---|---|
trx_id ==creator_trx_id | 可以访问该版本 | 成立,说明数据是当前这个事务更改的。 |
trx_id < min_trx_id | 可以访问该版本 | 成立,说明数据已经提交了。 |
trx_id > max_trx_id | 不可以访问该版本 | 成立,说明该事务是在ReadView生成后才开启。 |
min_trx_id <= trx_id<= max_trx_id | 如果trx_id不在m_ids中,是可以访问该版本的 | 成立,说明数据已经提交。 |
READ COMMITTED
:在事务中每一次执行快照读时生成ReadView。REPEATABLE READ
:仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。
READ COMMITTED
中,每执行一次select语句就会执行快照读生成ReadView
,然后数据库就会根据所生成的ReadView
以及ReadView
的版本链访问规则,到undo log
版本链中匹配数据,最终决定此次快照读返回的数据。RR隔离级别下,仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。而RR是可重复读,在一个事务中,执行两次相同的select语句,查询到的结果是一样的。
【MySql|数据库InnoDB-MVCC-多版本并发控制】MVCC与锁机制保证了数据库的隔离性。数据事务的其他性质及保证可以参考:
Mysql事务详解-[数据库的隔离级别、脏读、不可重复读、幻读以及ACID性质与redo log与undo log]
推荐阅读
- JAVA基础|JAVA经典垃圾收集器的优点缺点简单总结
- MySql|Mysql事务详解-[数据库的隔离级别、脏读、不可重复读、幻读以及ACID性质与redo log与undo log]
- sql|OA项目之我的会议(查询)
- java|自己的开源项目被尤雨溪写进演讲稿是一种什么体验()
- mysql|大数据处理与开发课程设计——纽约出租车大数据分析
- Java系列|ReentrantLock 可重入锁
- flask|(零八)Flask有手就行——数据库迁移Flask-Migrate
- spring|Springboot学习笔记
- 其他|Redis学习