前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布

MVCC

原创
作者头像
微凉墨夏
修改2021-03-02 18:08:47
7250
修改2021-03-02 18:08:47
举报
文章被收录于专栏:Java技术栏

什么是事务?

    事务是数据库管理系统(DBMS)执行过程中的一 个逻辑单位,由一个有限的数据库操作序列构成。

事务的四大特性:

        原子性(Atomicity) 

        一致性(Consistent) 

        隔离性(Isolation)

        持久性(Durable)

  1. 原子性 

一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作这就是事务的原子性。

  1. 一致性

事务的执行不能破坏数据库的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态。

如果数据库系统在运行过程中发生故障,有些事务尚未完成就被迫中断,这些未完成的事务对数据库所作的修改有一部分已经写入物理数据库,这时数据库就处于一种不正确状态,也就是不一致的状态。

  1. 隔离性

事务的隔离性是指在并发环境中,并发的事务是相互隔离的,一个事务的执行不能被其他事务干扰。不同的事务并发操作相同数据时,每个事务都有各自完成的数据空间,即一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能相互干扰。

  1. 持久性

            也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的,不能回滚。接下来的其它操作或故障不应该对其执行结果有任何影响。

         事务并发的三大问题其实都是数据库读一致性问题, 必须由数据库提供一定的事务隔离机制来解决。

MySQL InnoDB对事务隔离级别的支持程度

事务隔离级别

脏读

不可重复读

幻读

读未提交(read-uncommitted)

读未提交(read-uncommitted)

可重复读(repeatable-read)

是(对InnoDB不可能)

序列化/串行化(serializable)

MySQL Innodb中跟数据持久性、一致性有关的日志,有以下几种:

  • Bin Log:是mysql服务层产生的日志,常用来进行数据恢复、数据库复制,常见的mysql主从架构,就是采用slave同步master的binlog实现的
  • Redo Log:记录了数据操作在物理层面的修改,mysql中使用了大量缓存,修改操作时会直接修改内存,而不是立刻修改磁盘,事务进行中时会不断的产生redo log,在事务提交时进行一次flush操作,保存到磁盘中。当数据库或主机失效重启时,会根据redo log进行数据的恢复,如果redo log中有事务提交,则进行事务提交修改数据。
  • Undo Log: 除了记录redo log外,当进行数据修改时还会记录undo log,undo log用于数据的撤回操作,它记录了修改的反向操作,比如,插入对应删除,修改对应修改为原来的数据,通过undo log可以实现事务回滚,并且可以根据undo log回溯到某个特定的版本的数据,实现MVCC

如何保证一个事务中前后两次读取数据结果一致,实现事务隔离。

1.读取事务之前加锁,防止其他事务修改数据 这种方法被成为 LBC ( Lock Based Concurrency Control)。

2.生成一个数据请求时间点的一致性数据快照 (Snapshot),并用这个快照来提供一定级别(语句级或事 务级)的一致性读取 MVCC (Multi Version Concurrency Control)。

MVCC代表多版本并发控制。与MVCC相对的,是基于锁的并发控制

MVCC最大的优势:读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能

On-Line Transaction Processing联机事务处理过程(OLTP),也称为面向交易的处理过程,其基本特征是前台接收的用户数据可以立即传送到计算中心进行处理,并在很短的时间内给出处理结果,是对用户操作快速响应的方式之一。

MVCC的实现原理

MVCC实现原理主要是用到了的 四个隐式字段中的两个字段、undo日志 、Consistent Read View来实现的。

四个隐式字段

DB_TRX_ID:

6byte,最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID

DB_ROLL_PTR

7byte,回滚指针,指向这条记录的上一个版本(存储于rollback segment里)

DB_ROW_ID

6byte,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引

FLAG 

一个删除flag隐藏字段, 既记录被更新或删除并不代表真的删除,而是删除flag变了

MVCC是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存行的过期时间(或删除时间)。当然存储的并不是实际的时间值,而是系统版本号(system version number)。每开始一个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。

在REPEATABLE READ隔离级别下,MVCC具体是如何操作的。

  • SELECT InnoDB会根据以下两个条件检查每行记录:
    • InnoDB只查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。
    • 行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行,在事务开始之前未被删除。

只有符合上述两个条件的记录,才能返回作为查询结果

  • INSERT InnoDB为新插入的每一行保存当前系统版本号作为行版本号。
  • DELETE InnoDB为删除的每一行保存当前系统版本号作为行删除标识。
  • UPDATE InnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识

事务对一条记录的修改,会导致该记录的undo log成为一条记录版本线性表(链表),undo log的链首就是最新的旧记录,链尾就是最早的旧记录。

undo日志

undo log主要分为两种:

insert undo log

代表事务在insert新记录时产生的undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃

update undo log

事务在进行update或delete时产生的undo log; 不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除

对MVCC有帮助的实质是update undo log ,undo log实际上就是存在rollback segment中旧记录链,它的执行流程如下:

一、 比如有个事务在persion表插入了一条新记录,记录如下,name为Jerry, age为24岁,隐式主键是1,事务ID和回滚指针,我们假设为NULL。为演示,插入提交后,该undo log被删除

二、 现在来了一个事务1对该记录的name做出了修改,改为Tom

在事务1修改该行(记录)数据时,数据库会先对该行加排他锁

然后把该行数据拷贝到undo log中,作为旧记录,既在undo log中有当前行的拷贝副本

拷贝完毕后,修改该行name为Tom,并且修改隐藏字段的事务ID为当前事务1的ID, 我们假设从1开始,之后递增,回滚指针指向拷贝到undo log的副本记录,既表示我的上一个版本就是它

事务提交后,释放锁

三、 又来了个事务2修改person表的同一个记录,将age修改为30岁

在事务2修改该行数据时,数据库也先为该行加锁

然后把该行数据拷贝到undo log中,作为旧记录,发现该行记录已经有undo log了,那么最新的旧数据作为链表的表头,插在该行记录的undo log最前面

修改该行age为30岁,并且修改隐藏字段的事务ID为当前事务2的ID, 那就是2,回滚指针指向刚刚拷贝到undo log的副本记录

事务提交,释放锁

记录版本链

从上面,我们就可以看出,同一记录的多次修改,会导致该记录的undo log成为一条记录版本线性表,既链表,undo log的链首就是最新的旧记录,链尾就是最早的旧记录

Read View(读视图)

什么是Read View?(对照表?)

什么是Read View,Read View是session进行快照读操作的时候生产的读视图(Read View),在该session执行的快照读的那一刻,会生成数据库系统当前的一个快照。

Read View主要是用来做可见性判断的, 即当执行快照读的时候,对该记录创建一个Read View读视图,把它比作条件用来判断当前session能够看到哪个版本的数据,既可能是当前最新的数据,也有可能是该行记录的undo log里面的某个版本的数据。

Read View:执行查询时【所有】未提交的事务Id数组(数组里最小的id为min_id)和已创建的最大事务id(max_id:未提交、已提交)组成

mvcc遵循一个可见性算法,查询时候,需要用read-view和undo log 做对比得到结果

比较规则:

依次比较记录版本链中每一条记录,符合规则就返回该条数据,不符合根据回滚指针取链路中的下一条数据;

trx_id为记录版本链里的DB_TRX_ID

1、如果trx_id < min_id(落在绿色部分),表示这个版本是已经提交的事务生成的,这个数据肯定是可见的;

2、如果trx_id > max_id (落在红色部分),表示这个版本是由将来的启动的事务生成的,是肯定不可见的;

3、如果min_id <= trx_id <= max_id (落在黄色部分),那就包括两种情况

a、若trx_id在未提交的事务Id数组里,表示这个版本是由未提交的事务产生的,不可见,当前自己的事务是可见的;

b、若trx_id不在未提交的事务Id数组里,表示这个版本是已经提交的事务生成的,可见

简单概述:

        只能查找创建时间小于等于当前事务ID的数据,和删除时间大于当前事务ID的行

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档