MVCC(Multi-Version Concurrency Control,多版本并发控制 )是MySQL等数据库中用于实现并发控制的一种技术 ,是事务隔离级别的无锁实现方式。
mvcc原理实现的2个主要组件:
undo log(回滚日志) :undo log是MVCC实现的基础。它记录了数据被修改前的版本信息。在MySQL的InnoDB存储引擎中,undo log分为插入undo log和更新undo log 。插入undo log只在事务回滚时需要,事务提交后可立即删除;而更新undo log则会被MVCC机制用于构建数据的历史版本。比如在笔记中,记录了不同事务对 balance 字段修改前的数据版本,通过 db_trx_id 标记事务ID,db_roll_ptr 指向更早的版本。
Read View(读视图) :当一个事务执行快照读(如普通的SELECT语句,非锁定读)时,数据库会为该事务创建一个Read View。Read View中包含了当前活跃事务(未提交事务)的最小事务ID(min_trx_id)、最大事务ID(max_trx_id) 以及创建该Read View的事务ID(creator_trx_id)。
以隔离级别读已提交为例:
| 事务10 begin | 事务20 begin |
|---|---|
| #money=1000Update order set money=800 where id=1; | |
| Select * from order where id=1Commit;#moneyMoney=1000 | |
| Commit; 提交事务 |
Undo log里面:
| Id | money | db_trx_id | db_roll_ptr |
|---|---|---|---|
| 1 | 800 | 10 |
| Id | money | db_trx_id | db_roll_ptr |
|---|---|---|---|
| 1 | 1000 | 1 |
| Id | money | db_trx_id | db_roll_ptr |
|---|---|---|---|
| 1 | 500 | 0 | null |
而我们因为要进行查询,mysql给我们生成了一个Read View
| creator_trx_id | m_ids | min_trx_id | max_trx_id |
|---|---|---|---|
| 20 | 10, 20 | 10* | 21 |
| 当前事务id | 未提交事务的集合 | 未提交事务最小id | 未开始事务 |
判断标准: ①如果被访问的记录版本号db_trx_id等于Read-view中的creator_trx_id,说明这个事务是当前保存的。
②如果被访问的记录版本号db_trx_id小于min_trx_id,表明该版本是在事务开始之前保存进来的。
③如果被访问的记录版本号db_trx_id大于或等于max_trx_id,说明该事务是在当前事务开始之后保存进来的。
④如果被访问的记录版本号 db_trx_id 介于 min_trx_id 和 max_trx_id 之间,说明该数据版本对应的事务在当前事务开始时处于活跃(未提交)状态。在不同隔离级别下处理方式不同, 如读已提交隔离级别下,每次查询都会创建新的Read View,需要继续从undo log找合适版本;而在可重复读隔离级别下,第一次查询创建Read View后,后续查询复用该Read View,只要数据版本不满足前面三种可见情况,就从undo log获取可见版本 。
通过上面的判断发现只有在undo log 中db_trx_id=1时,是符合判断②逻辑的。所以得出money=1000;
读未提交:无需锁无需mvcc,因为修改数据直接修改数据源,会出现脏读.
读已提交:每次查询都会创建ReadView读取数据.
重复读:同样的查询只会第一次创建ReadView读取数据.
串行化:表锁.