MySQL中InnoDB通过MVCC实现事务隔离介绍

前言

之前文章中我们介绍过MySQL事务隔离级别及事务并发问题,当时说到InnoDB存储引擎通过多版本并发控制(Multiversion Concurrency Control 简称MVCC)机制解决了幻读问题,那我们今天就来看看到底是怎么解决的。
读这篇文章之前可以先了解一下MySQL中InnoDB数据结构

一、InnoDB引擎对隔离级别的支持

事务隔离级别脏读不可重复读幻读
读未提交(read-uncommitted)可能可能可能
不可重复读(read-committed)不可能可能可能
可重复读(repeatable-read)不可能不可能InnoDB不可能
串行化(serializable)不可能不可能不可能

隔离级别到底如何实现?

二、什么是 MVCC(多版本并发控制)

英文全称:
Multiversion concurrency control
白话解释:
并发访问(读或写)数据库时,对正在事务内处理的数据做 多版本的管理。以达到用来避免写操作的堵塞,从而引发读操 作的并发问题。
版本号管理
mvcc版本号是在行数据中记录(隐藏字段),DB_TRX_ID(数据行的版本号)、DB_ROLL_PT(删除版本号)
例如:mvcc隐藏字段

三、mysql中MVCC处理逻辑

1、数据新增
在事务开始的时候,会拿到一个全局事务ID(自增),然后在新增数据的时候,会在DB_TRX_ID(数据行的版本号)字段记录当前事务ID号。
执行:

//例如全局事务id从1开始自增;
begin;  //拿到事务id=1
insert into user(name, age) VALUE('bob',20);
insert into user(name, age) VALUE('jack',22);
commit;

运行结果:
我们的表中DB_TRX_ID字段会记录当前事务ID号
新增数据
2、删除数据
在事务开始的时候,会拿到一个全局事务ID(自增),然后在删除数据的时候,会在DB_ROLL_PT(删除版本号)字段记录当前事务ID号。
执行:

//例如目前全局事务id为3;
begin;  //拿到事务id=3
delete user where id=2;
commit;

运行结果:
我们的表中DB_ROLL_PT字段会记录当前事务ID号
清除数据
3、修改数据
在事务开始的时候,会拿到一个全局事务ID(自增),先把要修改的数据行进行copy操作,copy后的数据行中DB_TRX_ID字段设置成当前事务ID号,再把copy后的数据行中需要修改的字段进行修改,然后原来数据行中DB_ROLL_PT字段设置成当前事务ID号。
执行:

//例如目前全局事务id为5;
begin;  //拿到事务id=5
update user set age=18 where id=1;
commit;

运行结果:修改数据
4、数据查询
1)查找数据行版本号(DB_TRX_ID)小于或等于当前事务版本号的数据行,这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身的数据,这样才能确保取出来的数据,事务开始时没有修改和插入过。

2)查找删除版本号(DB_ROLL_PT)要么为NULL要么是大于当前事务ID的数据行,这样才能确保取出来的数据,是在事务开始时没有被删除过。
执行:

//例如目前全局事务id为8;
begin;  //拿到事务id=8
select * from user;
commit;

运行结果:
查询数据

四、MVCC版本控制案例解析

数据准备

//例如全局事务id从1开始自增;
begin;  //拿到事务id=1
insert into user(name, age) VALUE('bob',20);
insert into user(name, age) VALUE('jack',22);
commit;

执行结果:
插入数据
1、案例一
执行以下操作:

时间轴事务A事务B
1begin;-
2select * from user ;-
3-begin;
4-update user set age =28 where id =1;
5select * from user ;-

执行结果:
例如目前事务A拿到全局事务id为2,事务B拿到全局事务id为3;

时间轴1、2执行后得到结果为:
(1,bob,20;2,jack,22)

时间轴3,4执行结果:
案例一
时间轴5执行结果:
(1,bob,20;2,jack,22)
分析:
数据查询条件是,查找数据行版本号(DB_TRX_ID)小于或等于当前事务版本号的数据行,所以两次查询结果一致。

2、案例二
执行以下操作:

时间轴事务A事务B
1begin;-
2update user set age =28 where id =1;-
3-begin;
4-select * from user ;

执行结果:
例如目前事务A拿到全局事务id为2,事务B拿到全局事务id为3;
时间轴1、2执行后得到结果为:案例2
时间轴4执行结果:
(1,bob,20;2,jack,22)
分析:
数据查询条件是,查找数据行版本号(DB_TRX_ID)小于或等于当前事务版本号的数据行,但是现在看到这事务ID是大于的,为什么还是这个结果呢?那我们就要了解Undo log是做什么的了。

五、MVCC版本控制中Undo Log、Redo Log

1、Undo Log

  • Undo Log是什么:
    undo意为取消,以撤销操作为目的,返回指定某个状态的操作;
    undo log指事务开始之前,在操作任何数据之前,首先将需操作的数据备份到一 个地方 (Undo Log);

  • UndoLog是为了实现事务的原子性而出现的产物
    事务处理过程中如果出现了错误或者用户执行了 ROLLBACK语句,Mysql可以利用Undo Log中的备份将数据恢复到事务开始之前的状态

  • UndoLog在Mysql innodb存储引擎中用来实现多版本并发控制
    事务未提交之前,Undo保存了未提交之前的版本数据,Undo 中的数据可作为数据旧版本快照供其他并发事务进行快照读

UndoLog在案例二中的作用
在时间轴4执行中,对Undo中的数据进行读取返回(快照读),确保读取到的数据是事务开始前提交的数据
undolog
当前读、快照读

  • 快照读:
    SQL读取的数据是快照版本,也就是历史版本,普通的SELECT就是快照读
    innodb快照读,数据的读取将由 cache(原本数据) + undo(事务修改过的数据) 两部分组成
  • 当前读:
    SQL读取的数据是最新版本。通过锁机制来保证读取的数据无法通过其他事务进行修改
    UPDATE、DELETE、INSERT、SELECT … LOCK IN SHARE MODE、SELECT … FOR UPDATE都是当前读

2、Redo Log

  • Redo Log 是什么:
    Redo,顾名思义就是重做。以恢复操作为目的,重现操作;
    Redo log指事务中操作的任何数据,将最新的数据备份到一个地方 (Redo Log)
  • Redo log的持久:
    不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入redo 中。具体的落盘策略可以进行配置
  • RedoLog是为了实现事务的持久性而出现的产物
    防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的未入磁盘数据进行持久化这一特性。
    redo log

Redo log补充知识点

  • 指定Redo log 记录在{datadir}/ib_logfile1&ib_logfile2 可通过innodb_log_group_home_dir 配置指定目录存储
  • 一旦事务成功提交且数据持久化落盘之后,此时Redo log中的对应事务数据记录就失去了意义,所以Redo log的写入是日志文件循环写入的
    1、指定Redo log日志文件组中的数量 innodb_log_files_in_group 默认为2
    2、指定Redo log每一个日志文件最大存储量innodb_log_file_size 默认48M
    3、指定Redo log在cache/buffer中的buffer池大小innodb_log_buffer_size 默认16M
  • Redo buffer 持久化Redo log的策略, Innodb_flush_log_at_trx_commit:
    1、取值 0 每秒提交 Redo buffer --> Redo log OS cache -->flush cache to disk[可能丢失一秒内的事务数据]
    2、取值 1 默认值,每次事务提交执行Redo buffer --> Redo log OS cache -->flush cache to disk[最安全,性能最差的方式]
    3、取值 2 每次事务提交执行Redo buffer --> Redo log OS cache 再每一秒执行 ->flush cache to disk操作
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值