Mysql实现可重复读的方式——MVCC

Mysql实现可重复读的方式——MVCC

目录

简介

隐式字段

undo日志版本链

read-view一致性视图

MVCC比对规则

实例


 

简介

MVCC:(Multi-Version Concurrency Control)多版本并发控制

隐式字段

Mysql每一行数据都有几个隐藏的字段,用于标记本条数据的历史版本信息以及事务信息等。
DB_TRX_ID:最近修改(修改/插入)事务ID,记录创建这条记录/最后一次修改该记录的事务ID
DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本
DB_ROW_ID:隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引
实际还有一个删除flag隐藏字段, 既记录被更新或删除并不代表真的删除,而是删除flag变了

undo日志版本链

Mysql在执行一条条SQL语句的时候,对每一条数据的历史记录都会进行记录,采用的方式就是undo日志版本链。
例:
如下数据:
表:balance
id  name  account
1   lilei      3000
分别执行如下三条数据:
DB_TRX_ID(事务ID):100
update balance set name = lilei2 where id = 1;
commit;
DB_TRX_ID(事务ID):200
update balance set name = lilei3 where id = 1;
commit;
DB_TRX_ID(事务ID):300
update balance set name = lilei4 where id = 1;
commit;

则版本链信息如下:

read-view一致性视图

当一个select语句查询开始的时候,会生成当前事务的read-view一致性视图,视图规则为:所有未提交的事务ID组成的数组与已提交的最大的事务ID,格式如下:

[100,200],300

当其他事务对数据进行修改的时候,本事务的read-view一致性视图不会变化,保证了可重复读机制。

MVCC比对规则

1. 当前事务ID小于read-view中的最小事务ID,则本事务一定是已经提交过了的,可见。

2. 当前事务ID如果大于read-view中的最大事务ID,则本事务是在当前事务开始后新建的,不可见。

3. 当前事务ID小于等于read-view中的最大事务ID且大于等于read-view中的最小事务ID,分两种情况:

3.1 如果当前事务ID在数组中,则数据是由未提交得事务更新得,除事务本身以外,其他事务不可见

3.2 如果当前事务ID不在数组中,则数据是由已提交得事务更新得,可见。

实例

# Transaction 100# Transaction 200# Transaction 300# select 1# select 2
begin;begin;begin;begin;begin;
update test set c1 = '123' where id =1;    
 update test set c1 = '666' where id =5;   
  update account set name = 'lilei300' where id = 1;  
  commit;  
     
   

select name from account where id = 1;

read-view:[100,200],300

结果为:lilei300

 
update account set name = 'lilei1' where id = 1;    
update account set name = 'lilei2' where id = 1;    
   

select name from account where id = 1; 

read-view:[100,200],300

结果为:lilei300

 
     
commit;    
 update account set name = 'lilei3' where id = 1;   
 update account set name = 'lilei4' where id = 1;   
   

select name from account where id = 1;  

read-view:[100,200],300

结果为:lilei300

select name from account where id = 1; 

readview:[200], 300    

结果为:lilei2

     
 commit;   

 

### 验证 MySQL MVCC 的工作原理 为了理解并验证MySQL中的多版本并发控制(MVCC),可以创建具体的测试场景来观察不同事务之间的交互行为。这些实验能够展示MVCC如何处理写操作而不引起冲突。 #### 创建测试环境 首先,在具有`InnoDB`作为默认存储引擎的环境中设置两个会话窗口,分别代表不同的客户端连接到同一个数据库实例上执行SQL命令: ```sql -- 设置隔离级别为可重复取 (REPEATABLE READ) SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; ``` #### 测试案例 1:不可见更新 在一个会话中启动一个未提交的事务,并修改某些记录;而在另一个会话里尝试查询相同的记录集,应该看不到第一个会话所做的更改直到它被正式提交为止[^2]。 ##### Session A: ```sql START TRANSACTION; UPDATE employees SET salary = salary * 1.1 WHERE employee_id = 101; -- 增加工资但不提交 SELECT * FROM employees WHERE employee_id = 101; ``` ##### Session B: ```sql SELECT * FROM employees WHERE employee_id = 101; -- 应该返回原始数据而不是已更新的数据 ``` 当Session A最终发出COMMIT语句之后再让Session B重新运行上述查询,则可以看到最新的薪资变化情况。 #### 测试案例 2:防止幻影 此部分展示了即使有新行插入或删除的情况下,只要是在同一事务内多次取相同范围内的数据时都能得到一致的结果集合。 假设有一个名为employees的表,其中包含员工的信息以及他们的部门编号(dept_no)。 ##### Session C: ```sql START TRANSACTION; INSERT INTO employees VALUES ('John Doe', 'D009'); -- 插入一条新的记录但是并不立即提交 ``` ##### Session D: ```sql START TRANSACTION; SELECT COUNT(*) AS count_before, MAX(employee_name) as max_name FROM employees WHERE dept_no='D009'; -- 此处等待一段时间以便于其他会话完成其操作后再继续... SELECT COUNT(*) AS count_after, MAX(employee_name) as max_name FROM employees WHERE dept_no='D009'; ``` 如果在两次查询之间没有任何来自外部的影响因素干扰的话,那么这两个结果应当完全一样——即count_before等于count_after而且max_name也保持不变。这证明了在同一事务期间对于特定条件下的扫描总是能看到同样的视图而不会受到中途发生的变更影响。 通过以上两种方式可以有效地检验MySQLMVCC的实际运作状况及其特性表现形式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值