手机 登录asp网站,绵阳建设工程信息网站,医疗网站模板免费下载,延吉手机网站建设开发一 MVCC的作用
1.1 mvcc的作用
1.MVCC#xff08;Multiversion Concurrency Control#xff09;多版本并发控制。即通过数据行的多个版本管理来实现数据库的并发控制#xff0c;使得在InnoDB事务隔离级别下执行一致性读操作有了保障。
2.mysql中的InnoDB中实现了MVCC主要…一 MVCC的作用
1.1 mvcc的作用
1.MVCCMultiversion Concurrency Control多版本并发控制。即通过数据行的多个版本管理来实现数据库的并发控制使得在InnoDB事务隔离级别下执行一致性读操作有了保障。
2.mysql中的InnoDB中实现了MVCC主要是为了提高数据库的并发性能在无锁的情况下也能处理读写并发大大提高数据库的并发度。
3..MySQl中只有InnoDB支持MVCC其他存储引擎不支持
4.为了查询一些正在被其他事务更新的值的时候能够查到它们被更新之前的值这样做就能在查询的时候不必等待更新事务的提交。
在InnoDB中会对增删改操作自动添加排它锁因此两个事务不会出现脏写的情况也就是不会出现两个事务交叉着对同一条记录进行修改必须等待第一个事务提交才能进行第二个事务。
1.2 快照读与当前读的区别与联系
1.MVCC在InnoDB中的实现主要是为了提高数据库的并发性能用更好的方式处理读写冲突做到即使有读写冲突也能不加锁实现非堵塞并发读这个读指的是快照读而不是当前读。
2.当前读实质上是一种加锁的操作是悲观锁的体现而MVCC是采用乐观锁的一种方式
1.3 快照读
1.快照读顾名思义读取的是一份快照数据所以读到的并不一定是最新数据可能是历史数据。
2.简单的select查询就是快照读不加锁非阻塞读降低数据库的开销。
3.但是快照读在隔离级别是串行化级别是没有意义的因为串行化的sql都是排队执行的不存在并发所以就会变成当前读。
1.4 当前读
当前读获取的数据是最新数据而且在读取时不能被其他修改的所以会对读取的记录加锁来控制。
加锁的SELECT共享或排它锁或者对数据进行增删改操作自动添加排它锁都会进行当前读。
select * from ajisun where id 1 lock in share mode;// 或者select * from ajisun where id 1 for update;
1.5 mvcc可以解决问题 读写之间的堵塞问题提高事务的并发读写能力 降低了死锁的概率MVCC采用了乐观锁的方式读取数据的时候不需要加锁对于写操作也只要锁定必要的行 解决快照读问题当查询数据库某个时间节点的快照的时候只能查看到在这个节点之前提交的事务的结果而看不到时间点之后事务提交的更新结果
1.6 mvcc面试题mvcc是怎么实现的
mvcc 是多版本并发控制通过生成记录的历史版本解决幻读问题并提高数据库的性能无锁实现读写并发操作。
1.mvcc 的实现主要是通过三个隐藏字段undo log以及readView 实现的。
2.三个隐藏字段分别是隐藏主键事务ID回滚指针。
3.undo log是各个事务修改同一条记录的时候生成的历史记录方便回滚同时会生成一条版本链。
4.readView是事务在进行快照读的时候生成的记录快照用于判断数据的可见性。
5.描述readView 可见性判断规则。
二 MVCC实现原理
2.1 原理
MVCC的实现依赖于隐藏字段、Undo log、Read View
2.2 undo log
2.2.1 undo Log的作用
所谓的版本链就是在MVCC中多个事务对同一行记录进行更新会产生多个历史快照这些记录保存在Undo Log里这些undo日志通过回滚指针串联在一起。
undo log就是回滚日志在insert/update/delete变更操作的时候生成的记录方便回滚。
当进行insert操作的时候产生的undo log只有在事务回滚的时候需要如果不回滚在事务提交之后就会被删除。
当进行update和delete的时候产生的undo log不仅仅在事务回滚的时候需要在快照读的时候也是需要的所以不会立即删除只有等不再用到这个日志的时候才会被mysql purge线程统一处理掉delete操作也只是打一个删除标记并不是真正的删除)。
2.2.2 undo Log的组成
undo log的版本链对于使用InnoDB存储引擎的表来说它的聚簇记录中包含两个必要的索引列
1.trx_id每次事务对聚簇记录进行修改的时候就会将该事务的id复制给trx_id隐藏列
2.roll_pointer每次对每条聚簇索引进行改动的时候都会将旧的版本信息写入undo log中通过回滚指针就能找到记录修改前的信息。
2.2.3 undo Log的案例
1.假设两个事务id分别为10、20的事务分别对这条记录进行Update操作。 2.每次对记录进行改动都会记录一条undo log每个undo log都包含创建它的事务id每条undo log都会有一个roll pointerINSERT操作不会有因为插入没有更新的版本这些undo log通过roll pointer连接起来串成一个链表这个链表就成为undo log 版本链。
3.如下图 2.3 隐藏字段
除了我们正常业务涉及的字段外InnoDB在内部向数据库表中添加三个隐藏字段:
1.DB_TRX_ID6-byte的事务ID。插入或更新行的最后一个事务的事务ID
2.DB_ROLL_PTR7-byte的回滚指针。就是指向对应某行记录的上一个版本在undo log中使用。
3.DB_ROW_ID6-byte的隐藏主键。如果数据表中没有主键那么InnoDB会自动生成单调递增的隐藏主键表中有主键或者非NULL的UNIQUE键时都不会包含 DB_ROW_ID列。
如上面的表没有设计primary key,其中id/name/city是我们的业务字段那么加上隐藏字段应该如下 2.4 ReadView
2.4.1 ReadView的作用
ReadView 是事务快照读的时候产生的数据读视图在该事务执行快照读的那一刻会生成一个数据系统当前的快照记录并维护系统当前活跃事务的id事务的id值是递增的。
Read View就是事务在使用MVCC机制在进行快照读操作时产生的快照ReadView 的最大作用就是判断数据的可见性当某个事务执行快照读的时候会对此记录创建一个ReadView 的视图在整个事务期间根据某些条件判断该事务能够看到的版本链上的哪条历史数据。
2.4.2 ReadView的组成 creator_id创建这个Read View的事务id trx_ids表示创建这个Read View的时候正在活跃的事务id列表 up_limit_id活跃的事务中最小的id low_limit_id表示生成low_limit_id时系统应该分配给下一个事务的id值low_limit_id是系统最大的事务id而不是活跃的最大事务id
***low_limit_id并不是trx_ids的最大值而是系统能够分配的事务id最大值事务id是递增分配的并且只有事务在进行增删改操作的时候才会分配事务ID。比如现在有1 2 5三个事务那么id为5的事务提交后一个新事务在生成ReadView的时候trx_ids就包括1 2up_limit_id就是1low_limit_id就是6 此时如果有事务创建Read View则
trx_ids[trx2, trx3, trx5, trx8]up_limit_idtrx2low_limit_idtrx81
2.4.3 ReadView的判断流程
当查询一条数据的时候系统
首先获取查询操作的事务的版本号获取当前系统的ReadView将查询到的数据与ReadView中的事务版本号进行比较如果不符合ReadView的规则则通过回滚指针形成的Undo Log版本链从undo log中获取符合规则的历史快照返回符合规则的数据
快照记录创建这个Read View的事务id、活跃的事务中最小的id、系统最大的事务id并且InnoDB会为每个事务构建了一个数组用来记录并维护系统当前活跃事务的ID活跃指的是启动了还没有提交等到访问某条记录的时候就可以根据上面记录的内容判断记录版本对当前事务可不可见
1.如果Read View的creator_id和当前事务的id相同则意味着当前事务在访问它修改过的id所以该记录版本可以被事务访问
2.如果当前访问版本记录的trx_id小于Read View的up_limit_id则意味着修改该数据版本的事务已经提交所以该版本的记录可以被当前事务访问
3.如果当前访问版本记录的trx_id大于等于Read View的low_limit_id则意味着创建该数据版本的事务是在ReadView生成之后才出现的因此当前事务不能访问
4.如果当前访问版本记录的trx_id在Read View的up_limit_id和low_limit_id之间则需要判断trx_id是否在Read View的trx_ids活跃事务列表中如果在则说明事务还没有提交当前事务不能访问否则可以访问
5.如果某个版本对当前事务不可见那么顺着版本链找到下个版本记录然后继续上面的对比规则直到找到版本链中的最后一个版本如果最后一个版本都不可见那么该条记录对此事务完全不可见也就查不到这个记录。
2.5 不同隔离级别使用Readview
1.读未提交能够读取未提交的事务修改的数据所以直接读取最新的记录就可以不必使用MVCC
2.读已提交不能读取未提交的事务修改的数据并且不能进行重复读取事务中每次快照读都会新生成一个快照和ReadView,这就是我们在RC级别下的事务中可以看到别的事务提交的更新的原因。
3.可重复读不能读取未提交的事务修改的数据并且能进行重复读取所以只在第一次查询的时候获取一次ReadView之后查询都只查看已经生成的ReadView副本
4.可串行化InnoDB规定使用加锁的方式来访问记录通过加锁的方式让所有sql都串行化执行了也是读最新的不存在快照读ReadView。
https://www.cnblogs.com/tod4/p/17384677.html
MySQL进阶系列多版本并发控制mvcc的实现
2.6 mvcc解决幻读问题
MySQL在Repeatable Read隔离级别下是可以解决幻读问题的解决的方案有两种
1.使用MVCC进行快照读写使用临键锁。添加的临键锁不会影响快照读只会影响到想要获取锁的读操作
2.读写加锁也就是使用可串行化的隔离模式。
2.6.1 mvcc解决幻读
读操作利用多版本并发控制MVCC写操作加锁。
MVCC就是生成一个ReadView通过ReadView能够找到符合条件的记录版本历史版本由undo log提供查询查询语句执行查询已经提交的事务做出的更改对于没由提交的事务和ReadView创建之后的事务做出的更改是看不到的。而写操作肯定是针对的最新版本的记录因此读记录的历史版本和写操作的最新记录版本并不会冲突也就是采用MVCC时读写操作并不会冲突。
普通的SELECT语句在READ COMMITTED 和 REPEATABLE READ隔离级别下的读操作就是利用MVCC进行的读
1.READ COMMITTED由于不会读取没有提交的事务修改的数据版本因此避免了脏读问题
2.REPEATABLE READ由于不会读取Read View创建之后的事务更改的数据(一个事务只有在第一次执行SELECT语句才会生成一个Read View之后的SELECT语句都在复用)因此避免了可重复读和幻读问题。
2.6.2 通过加锁的方式
读、写操作都采用加锁的方式
在一些业务场景中不允许读取数据的历史版本即每次都需要去读取磁盘中最新的数据这样也就意味着读操作也需要和写操作一样排队执行。
如此一来脏读和不可重复读问题都得到了解决因为读操作和写操作的串行执行不会出现一个事务读取另一个未提交事务的数据以及一个事务读取过程中另一个事务修改数据提交导致前一个事务前后读取数据不一致的情况第二个事务根本无法开始。
****但是幻读问题有些尴尬试想一个事务在进行读操作因此给表中的一定范围内的数据加锁但是另一个事务要写的这个幻影数据可不在这个范围里面也就是两个读写操作并不会冲突仍然会出现幻读问题解决这一个问题的办法就是写操作使用临键锁