目次一 MVCC的作用1.1 mvcc的作用1.MVCC(Multiversion Concurrency Control)多版本并发控制。即通过数据行的多个版本管理来实现数据库的并发控制,使得在InnoDB事务隔离级别下执行[code]划一性读[/code]操作有了保障。 2.mysql中的InnoDB中实现了MVCC重要是为了进步数据库的并发性能,在无锁的情况下也能处置惩罚读写并发,大大进步数据库的并发度。 3..MySQl中只有InnoDB支持MVCC,其他存储引擎不支持 4.为了查询一些正在被其他事务更新的值的时间,能够查到它们被更新之前的值,如许做就能在查询的时间不必期待更新事务的提交。 在InnoDB中,会对增删改操作主动添加排它锁,因此两个事务不会出现脏写的情况,也就是不会出现两个事务交错着对同一条记录进行修改,必须期待第一个事务提交才能进行第二个事务。 1.2 快照读与当前读的区别与接洽1.MVCC在InnoDB中的实现重要是为了进步数据库的并发性能,用更好的方式处置惩罚读写辩论,做到即使有读写辩论,也能不加锁实现非堵塞并发读,这个读指的是[code]快照读[/code]而不是[code]当前读。[/code] 2.当前读实质上是一种加锁的操作,是悲观锁的表现;而MVCC是接纳乐观锁的一种方式 1.3 快照读1.快照读,顾名思义读取的是一份快照数据,所以读到的并不一定是最新数据,可能是历史数据。 2.简单的select查询就是快照读,不加锁非壅闭读,低落数据库的开销。 3.但是快照读在隔离级别是串行化级别是没有意义的,由于串行化的sql都是排队执行的,不存在并发,所以就会变成当前读。 1.4 当前读当前读获取的数据是最新数据,而且在读取时不能被其他修改的,所以会对读取的记录加锁来控制。 [code]加锁的SELECT(共享或排它锁)[/code]大概[code]对数据进行增删改操作(主动添加排它锁)[/code]都会进行[code]当前读。[/code] [code]select * from ajisun where id > 1 lock in share mode;</code><code>// 大概</code><code>select * from ajisun where id >1 for update;[/code]1.5 mvcc可以办理题目
1.6 mvcc口试题:mvcc是怎么实现的mvcc 是多版本并发控制,通过天生记录的历史版本办理幻读题目,并进步数据库的性能,无锁实现读写并发操作。 1.mvcc 的实现重要是通过三个隐蔽字段,undo log以及readView 实现的。 2.三个隐蔽字段分别是隐蔽主键,事务ID,回滚指针。 3.undo log是各个事务修改同一条记录的时间天生的历史记录,方便回滚,同时会天生一条版本链。 4.readView是事务在进行快照读的时间天生的记录快照,用于判断数据的可见性。 5.形貌readView 可见性判断规则。 二 MVCC实现原理2.1 原理 MVCC的实现依赖于:[code]隐蔽字段[/code]、[code]Undo log[/code]、[code]Read View[/code] 2.2 undo log2.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复制给[code]trx_id[/code]隐蔽列 2.roll_pointer:每次对每条聚簇索引进行改动的时间,都会将旧的版本信息写入[code]undo log[/code]中,通过回滚指针就能找到记录修改前的信息。 2.2.3 undo Log的案例 1.假设两个事务id分别为10、20的事务分别对这条记录进行[code]Update[/code]操作。 2.每次对记录进行改动,都会记录一条[code]undo log[/code],每个[code]undo log[/code]都包罗创建它的事务id,每条undo log都会有一个[code]roll pointer[/code](INSERT操作不会有,由于插入没有更新的版本),这些[code]undo log[/code]通过[code]roll pointer[/code]连接起来,串成一个链表,这个链表就成为[code]undo log 版本链。[/code] [code]3.如下图:[/code] 2.3 隐蔽字段除了我们正常业务涉及的字段外,InnoDB在内部向数据库表中添加三个隐蔽字段: 1.DB_TRX_ID:6-byte的事务ID。插入或更新行的最后一个事务的事务ID 2.DB_ROLL_PTR:7-byte的回滚指针。就是指向对应某行记录的上一个版本,在undo log中使用。 3.DB_ROW_ID:6-byte的隐蔽主键。如果数据表中没有主键,那么InnoDB会主动天生单调递增的隐蔽主键(表中有主键大概非NULL的UNIQUE键时都不会包罗 DB_ROW_ID列)。 如上面的表没有设计primary key,此中id/name/city是我们的业务字段,那么加上隐蔽字段应该如下 2.4 ReadView2.4.1 ReadView的作用 ReadView 是事务快照读的时间产生的数据读视图,在该事务执行快照读的那一刻,会天生一个数据系统当前的快照,记录并维护系统当前活跃事务的id,事务的id值是递增的。 [code]Read View[/code]就是事务在使用MVCC机制在进行快照读操作时产生的快照,ReadView 的最大作用就是判断数据的可见性,当某个事务执行快照读的时间,会对此记录创建一个ReadView 的视图,在整个事务期间根据某些条件判断该事务能够看到的版本链上的哪条历史数据。 2.4.2 ReadView的组成
low_limit_id 并不是trx_ids的最大值,而是系统能够分配的事务id最大值,事务id是递增分配的,而且只有事务在进行增删改操作的时间才会分配事务ID。好比如今有1 2 5三个事务,那么id为5的事务提交后,一个新事务在天生ReadView的时间,trx_ids就包括1 2,up_limit_id就是1,low_limit_id就是6 此时如果有事务创建Read View,则
2.4.3 ReadView的判断流程 当查询一条数据的时间,系统
快照记录创建这个Read View的事务id、活跃的事务中最小的id、系统最大的事务id,而且InnoDB会为每个事务构建了一个数组,用来记录并维护系统当前[code]活跃事务[/code]的ID(活跃指的是启动了还没有提交),等到访问某条记录的时间,就可以根据上面记录的内容判断记录版本对当前事务可不可见: 1.如果当前被访问记录的trx_id属性值与ReadView中的creator_trx_id值相同,说明当前事务修改的记录就是在当前事务下操作的,那固然是对我们可见的了,因此可以修改这条记录 2.如果当前被访问记录的trx_id属性值小于ReadView中up_limit_id值,说明(天生该版本的事务在该事务天生readView之间已经提交) 即当前事务在开启的时间,这条记录最近依次被其他事务操作的事务已经提交了,所以对这条记录对我们来说也是可以见,可以修改 3.如果当前被访问记录的trx_id属性值大于大概便是ReadView中low_limit_id值,说明(天生该版本的事务在当前事务天生readView之后才开启) 即:我们开启事务未修改该记录之前,已经有别的一个事务开启,而且正在修改该事务了,因此,这条记录对我们来说依然是不可见的,我们不能修改。 4.如果当前被访问记录的trx_id属性值介于ReadView中 up_limit_id 和 low_limit_id 之间的话,那么此时就必要分情况讨论了,此时我们应该分析该trx_id是否在 trx_ids 中 如果存在,说明(创建ReadView时,天生该版本的事务还处于活跃状态) 即:当前已经有其它的事务正在修改该条记录,而且还未提交,此时这条记录对我们不可见 如果不存在,说明((创建ReadView时,天生该版本的事务已经提交) 即:此时没有事务操作该条记录,我们可以修改该条记录 5.如果某个版本对当前事务不可见,那么顺着版本链找到下个版本记录,然后继续上面的对比规则,直到找到版本链中的最后一个版本,如果最后一个版本都不可见,那么该条记录对此事务完全不可见,也就查不到这个记录。 2.5 差别隔离级别使用Readview1.读未提交:能够读取未提交的事务修改的数据,所以直接读取最新的记录就可以,不必使用MVCC 2.读已提交:不能读取未提交的事务修改的数据,而且不能进行重复读取,事务中,每次快照读都会新天生一个快照和ReadView,这就是我们在RC级别下的事务中可以看到别的事务提交的更新的缘故原由。 3.可重复读:不能读取未提交的事务修改的数据,而且能进行重复读取,所以只在第一次查询的时间获取一次[code]ReadView[/code],之后查询都只查看已经天生的[code]ReadView副本[/code] 4.可串行化:InnoDB规定使用加锁的方式来访问记录,通过加锁的方式让全部sql都串行化执行了,也是读最新的,不存在快照读ReadView。 2.6 mvcc办理幻读题目MySQL在[code]Repeatable Read[/code]隔离级别下是可以办理幻读题目的,办理的方案有两种: 1.使用MVCC进行快照读,写使用[code]临键锁。[/code]添加的临键锁不会影响快照读,只会影响到[code]想要获取锁的读操作[/code] 2.读写加锁,也就是使用可串行化的隔离模式。 2.6.1 mvcc办理幻读 读操作利用[code]多版本并发控制[/code]([code]MVCC[/code]),写操作加[code]锁。[/code] [code]MVCC[/code]就是天生一个[code]ReadView[/code],通过[code]ReadView[/code]能够找到符合条件的记录版本(历史版本由[code]undo log[/code]提供查询),查询语句执行查询已经提交的事务做出的更改,对于没由提交的事务和[code]ReadView[/code]创建之后的事务做出的更改是看不到的。而写操作肯定是针对的[code]最新版本的记录[/code],因此读记录的历史版本和写操作的最新记录版本并不会辩论,也就是接纳MVCC时,读写操作并不会辩论。 平凡的SELECT语句在READ COMMITTED 和 REPEATABLE READ隔离级别下的读操作就是利用MVCC进行的读 1.READ COMMITTED:由于不会读取没有提交的事务修改的数据版本,因此制止了脏读题目 2.REPEATABLE READ:由于不会读取[code]Read View[/code]创建之后的事务更改的数据(一个事务只有在第一次执行SELECT语句才会天生一个[code]Read View[/code],之后的SELECT语句都在复用),因此制止了可重复读和[code]幻读题目。[/code] 2.6.2 通过加锁的方式 读、写操作都接纳加锁的方式 在一些业务场景中,不允许读取数据的历史版本,即每次都必要去读取磁盘中最新的数据,如许也就意味着[code]读操作[/code]也必要和[code]写操作[/code]一样排队执行。 如此一来,[code]脏读[/code]和[code]不可重复读[/code]题目都得到了办理,由于读操作和写操作的串行执行,不会出现一个事务读取另一个未提交事务的数据以及一个事务读取过程中另一个事务修改数据提交导致前一个事务前后读取数据差别等的情况(第二个事务根本无法开始)。 ****但是,[code]幻读[/code]题目有些尴尬,试想一个事务在进行读操作,因此给表中的一定范围内的数据加锁,但是另一个事务要写的这个[code]幻影数据[/code]可不在这个范围内里,也就是两个读写操作并不会辩论,仍然会出现[code]幻读题目[/code],办理这一个题目的办法就是写操作使用[code]临键锁[/code] 到此这篇关于mysql中mvcc的详细使用的文章就介绍到这了,更多相关mysql mvcc内容请搜刮脚本之家从前的文章或继续浏览下面的相关文章希望各人以后多多支持脚本之家! 来源:https://www.jb51.net/database/3270959tw.htm 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |
|手机版|小黑屋|梦想之都-俊月星空
( 粤ICP备18056059号 )|网站地图
GMT+8, 2025-7-2 08:52 , Processed in 0.032740 second(s), 18 queries .
Powered by Mxzdjyxk! X3.5
© 2001-2025 Discuz! Team.