苏州智能网站开发,找山东制作app公司,广西建设领域证书查询官方网站,画册宣传册设计公司MySQL理解MVCC #x1f604;生命不息#xff0c;写作不止 #x1f525; 继续踏上学习之路#xff0c;学之分享笔记 #x1f44a; 总有一天我也能像各位大佬一样 #x1f3c6; 博客首页 怒放吧德德 To记录领地 #x1f31d;分享学习心得#xff0c;欢迎指正#xff…MySQL理解MVCC 生命不息写作不止 继续踏上学习之路学之分享笔记 总有一天我也能像各位大佬一样 博客首页 怒放吧德德 To记录领地 分享学习心得欢迎指正大家一起学习成长 转发请携带作者信息 怒放吧德德 一个有梦有戏的人 文章目录 MySQL理解MVCC简介理解MVCCundo日志版本链read-view机制版本链对比规则 案例理解可重复读时刻6查询时刻9查询时刻13查询时刻14查询 读已提交时刻9查询时刻13查询 总结 转发请携带作者信息
怒放吧德德 一个有梦有戏的人 简介
多版本并发控制MVCCMulti-Version Concurrency Control是一种常用于数据库管理系统的并发控制方法MySQL数据库中的InnoDB存储引擎就实现了这种技术。MVCC通过在每个事务中对数据进行版本控制来实现多个事务的高效并发执行增强了数据库的读写性能并且减少了锁的需求。
理解MVCC
在MySQL的可重复读的隔离级别中同样的SQL查询语句在同一个事务中查出来的数据是一致的其他事务对这些数据进行修改当前事务是不可见的。这个隔离级别就是由MVCC机制来实现的。对一行数据并不会通过对读和写加互斥锁来保证隔离性避免了频繁加锁互斥而串行化隔离级别是通过读写互斥实现。 MySQL中读以提交和可重复读隔离级别都是通过MVCC。 undo日志版本链
undo日志版本链是指一行数据被多个事务依次修改后为了保持数据修改之前版本的可访问性InnoDB不会直接覆盖旧数据。会将数据的旧版本保存到undo日志中并且用隐藏字段trx_id事务id和roll_pointer回滚指针将这些日志串联起来成为一组历史版本链。 这个undo日志不只是保存单个版本而是随着时间推移和更多事务的执行可能保存同一数据项的多个历史版本。这些历史版本形成一个链条称为版本链。当需要某个记录的历史状态时可以通过回滚undo日志中的操作来获取旧版本数据或者在不同隔离级别的读取事务中适当地提供旧数据以此来保证一致性读取。 如下图可以很好的理解什么是undo日志版本链 如上图我们在插入数据的时候会开启事务所以会带着一个事务id接着对这条数据进行修改MySQL也会将修改的数据加上事务id以及回滚指针(roll_pointer)并且由这个回滚指针来指向上一个事务的旧数据版本这样就构成了日志版本链。 read-view机制
read-view机制是InnoDB存储引擎实现MVCC的一种来创建一致性读取视图的技术。主要作用是用来确保可重复读和读已提交的隔离级别下事务能够读到一致的数据快照即使其他事务在对数据进行修改。当一个事务想要执行一致性读取操作时候InnoDB通过多版本并发控制MVCC来保存数据的多个版本每个版本都有一个唯一的事务IDtrx_id与之关联。read-view机制就会创建一个视图这个视图是由执行查询时所有未提交的事务id数组组成数组最小的事务id为min_trx_id和已创建事务最大id为max_trx_id组成还有一个creator_trx_id用来表示生成该read-view的事务ID。 以上图示read-view机制的区间。
版本链对比规则
1、如果trx_idmin_trx_id表示生成该版本的事务在事务开始之前已经提交则该版本对事务可见。2、如果trx_idmax_trx_id表示生成该版本的事务在事务开始后才开始则该版本对事务不可见。3、如果min_trx_id≤trx_id≤max_trx_id则需要判断是否在视图数组trx_ids中。
1)、如果trx_id在视图中表示生成该版本是还没提交的事务因此该版本对事务不可见。2)、如果trx_id不在视图中表示生成该版本的事务是已提交的因此该版本对事务可见。 对于删除的情况会将版本链的最新数据复制一份然后将trx_id修改成删除操作的trx_id同时会在记录的头信息的标记位(delete_flag)上设置true用来表示已经删除在查询时如果对应记录的delete_flag为true则表示已经被删除就不会返回数据。 案例理解
接下来我们通过一个案例来理解。(本次通过上篇文章所用到的数据表来作为案例)我们假设有三个事务根据时间顺序会执行不同操作这里在如下的excel图中会有时刻来标记以及提交的时间点不同由此案例来了解MVCC机制是如何通过undo日志版本链和read-view机制工作的。并且介绍可重复读以及读已提交的MVCC机制。
可重复读
首先假设我们插入一条新的数据id12。然后我们有几个事务在执行各种操作并且都有相应的事务id具体的执行过程如下的excel图用来明确表示各个事务在时间戳的执行流程。 注这里需要注意一下begin/start transation命令并不是一个事务的起点具体真正开启事务是在执行到第一个修改操作InnoDB表的语句这时候才会有事务idMySQL内部是按照事务的启动顺序来分配事务id的。 时刻6查询
首先来看一种情况事务id100和101执行了更新操作但是没提交事务id102对id12进行了更新并且提交事务我们通过另一个会话进行查询id12的这条记录可见查出的first_name是102更新的数据。 我们来深入了解这MVCC机制是如何从undo日志版本链中进行比对获取这个102所更新的数据。如下图首先我们需要知道read-view所选中的min_trx_id和max_trx_id。通过当前系统中活跃的最小事务id从表格中可以看出min_trx_id是事务100已创建事务最大id为max_trx_id是事务102100101是未提交的活跃事务。read-view[100, 101], 102。
read-view {m_ids: [100, 101], // 事务100和事务101均未提交min_trx_id: 100, // 活跃未提交事务中最小的事务IDmax_trx_id: 102, // 已创建事务最大事务的IDcreator_trx_id: 102 // 创建这个read-view的当前事务的ID
}从日志版本链中看出事务102修改后会将回滚指针指向事务id为60上。然后就是进行版本链比对当前row的trx_id102刚好是等于max_trx_id接着需要判断这个102事务id是否在视图上显然102是不在[100101]中所以就会认为这条数据是可见的于是输出的值就是102这个事务的数据。
时刻9查询
我们接着往下走事务id为100的事务执行了两次对id为12的记录进行更新两次更新之后事务还没提交此时select 1会话又进行了一次查询。此时的查出来的数据依然是Liyongde依旧是事务102更新的数据。 我们再来分析这个过程。此时如下图read-view[100,101], 102。 根据版本链最新的数据是事务100更新的数据“Li2”但是根据版本链规则判断事务id100属于视图数组里面并且是没有提交的于是就往版本链指向的版本进行判断直到到达事务id102的这条记录不属于视图数组中认为是可见的因此返回的数据是“Liyongde”。
时刻13查询
接着看下一种情况事务100提交了随即事务101进行了一次更新并且不提交此时数据库的数据肯定是“Li2”之后select 1进行查询id12的记录此时的read-view又是否会发生变化呢得到的结果又是什么呢 可见查出来的数据还是“Liyongde”这是符合可重复读隔离级别的。还是需要通过undo日志版本链的规则来进行研究为什么得到的数据还是事务102提交的数据。先确定视图数组在可重复读级别下同事务中的read-view是不会发生变化。所以依然是[100,101], 102。 此时数据库id12是“Li2”但是查出来的数据还是“Liyongde”这是MVCC机制通过日志版本链的比对规则从而达到可重复读的隔离机制。首先当前的trx_id101而101处于min_trx_id与max_trx_id之间进一步判断是在视图里面所以不可见依此类推直到102不在视图中则得到的记录是“Liyongde”。因为一致性视图在同事务并不会发生变化因此即便直到100101102三个事务全部都提交之后Select 1查询得到的数据依旧是“Liyongde”。 注在可重复读级别下同事务中的read-view是不会发生变化。 这是因为可重复读的设计原则就是确保在同一个事务执行过程中所看到的数据总是与事务在启动时看到的数据保持一致。当事务启动时它会创建一个read-view这个read-view在事务的整个生命周期内都是固定的不会随着其他事务的提交或修改而改变。这样即使在事务执行期间有其他事务修改了数据当前事务所看到的数据仍然与启动时一致从而保证了数据的可重复读性。因此在可重复读的隔离级别下同一个事务的read-view是不会变化的。 时刻14查询
如果此时有个新的事务Select 2这个事务也是没有分配事务id一直下来也没有执行查询操作直到100102都提交之后在执行了查询。那么此时的查询结果会是什么 一致性视图read-view的状态取决于事务的启动时刻。根据excel图我们可以知道创建的read-view数据以及日志版本链如下图。 根据版本连的对比可以得出此时事务查出的数据是“Li2”。当数据库事务开启之后的头一次查询实际上read-view就已经创建了。我们通过以下例子来测试这个结果。 因为1是在修改之前进行了查询此时就已经创建了一致性视图接着进行修改值哪怕已经提交了查出来的结果依然是之前的数据而2是在修改提交之后才进行的查询此时创建的一致性视图就已经是更新过的事务数据。
读已提交
如上的案例我们知道在可重复读的隔离机制下read-view是在开启事务的第一次查询就已经创建了并且是直到事务的结束之前是不会发生变化。而接下来要介绍的读已提交隔离级别就有点不同主要是read-view的创建在读已提交的隔离级别下read-view会在每次的查询的时候进行变化。
时刻9查询
根据上面的excel图在时刻9的查询中我们可以得出此时创建的read-view事务102是提交的事务100和101都是活跃未提交的事务所以活跃数组则是[100, 101]当前事务为102min_trx_id100max_trx_id102。接着就是一样的进行日志版本对比对比规则与上文提到的方式是一致的102不在视图中所以数据可见最后返回的是“Liyongde”。
时刻13查询
接着再来看看时刻13的情况这个时候事务100也提交了因为读已提交的read-view会在每次的查询发生变化那么此时活跃事务就剩下了101所以数组是[101]当前事务为102min_trx_id101max_trx_id102。接着就是判断了根据规则进行比对最新的版本链中是事务id101其是落在视图中所以是不可见的数据接着往上个版本看事务id100是小于min_trx_id因此此条数据是可见的。
总结
MVCC是一种用于解决数据库并发问题的乐观锁技术多版本并发控制通过保存数据在某个时间点的快照来实现。换句话说读操作不会阻塞写操作写操作也不会阻塞读操作以此来提高数据库性能。在每次对数据的操作都用在undo日志版本链中进行。
创作不易如有错误请指正感谢观看记得点赞哦
转发请携带作者信息 怒放吧德德 一个有梦有戏的人