五分钟了解mysql脏读幻读不可重复读mvcc(代码片段)

androidstarjack androidstarjack     2023-01-19     500

关键词:

点击上方关注 “终端研发部”
设为“星标”,和你一起掌握更多数据库知识

首先对多事务并发的问题的思考

对 innodb引擎执行流程 和 buffer pool 足够了解的话,那一定知道mysql系统在初始化的时候bufferpool会将内存分为多个缓存页,此时的free链表都是空的;在对数据做操作的时候,就会将磁盘的数据页加载到内存的缓存页中去,此时这个缓存的描述信息就会从free链表中移除、同时将数据页信息放入lru冷链中和flush链表中;然后我们开始操作数据后,会记录undolog事务日志、redolog和binlog,最后刷盘。如果是commit之前宕机、可以通过redolog恢复之前的操作;如果是commit后出现问题,则会通过undolog来回滚。一个事务的执行流程大抵如此。

那多个事务并发运行的时候呢?n个用户同时触发一系列操作又会出现什么问题?比如:

1、多个事务并发对缓存页里的一行数据进行更新,这个冲突怎么处理?是否要加锁?

2、有事务在对一行数据做更新,其它事务在查询这行数据,这里的冲突怎么处理?

脏读、写

数据库里面有一个数据值为null,此时第一个线程将他修改为了A,这时候第二个事务来了,在内存页将它修改成了B。此时A突然回滚了,值成了最开始log里面记录的null,第二个线程丢改的值丢失了,这就叫脏写

数据库里面有一个数据值为null,此时第一个线程将他修改为了A,这时候第二个事务来了,在内存页查出来了这个A值。此时A突然回滚了,这个时候第二个线程的业务需要再查询一次,得到的却是null值,就很有可能影响之前的业务逻辑,这就是脏读

无论是脏写还是脏读,都是因为一个事务去更新或者查询了另外一个还没提交的事务更新过的数据。但由于另外一个事务还没提交,所以他随时可能会反悔会回滚,那么必然导致你更新(查询)的数据就没了。

不可重复读

emmm …. 不可重复读这个东西吧,你说他有问题他也有问题,你说他没问题他也没问题,不过mysql设计了一套机制来避免不可重复度的问题。上面的幻读幻写的本质就是操作了其他事务没提交的写数据。而不可重复读呢,举个例子:事务A在执行过程中查询一个数据是null,此时另一个事务修改为B提交后,事务A再次查出来就是值B,现在又一个线程修改为C提交后,事务A再次查出来就是值C,每次查出来的数据都不一样。那这到底是有问题还是没问题呢,仁者见仁智者见智吧!等会我会讲下mysql是如何规避这个问题的,mysql设计的比较高明。

幻读

幻读特指的是你查询到了之前查询没看到过的数据!比如查询月薪高于5000的人有10个,其他事务插入了几条数据后,此时查出了12条。那就会自我怀疑为啥一样的语句,前后两次查出的数据不一样了。

事务隔离级别

这里说的SQL标准的事务隔离级别,并不是MySQL的事务隔离级别,MySQL在具体实现事务隔离级别的时候会有点差别。SQL标准中规定了4种事务隔离级别,就是说多个事务并发运行的时候,不同的隔离级别是可以避免不同的事务并发问题的这4种级别包括了:read uncommitted(读未提交),read committed(读已提交),repeatable read(可重复读),serializable(串行化)。

read uncommitted:其他事务写操作没提交时,你只能读不能写。(这样不会脏写,可是会有脏读啊,一般没人用这个)
read committed:其他事务没提交时,你无法读或写。(俗称:RC,杜绝了脏读脏写,但还会幻读和不可重复读)
repeatable read:不会发生脏写、脏读和不可重复读,但还有幻读。(俗称:RR)
serializable:多个事务操作同一份数据时,会串行化,避免了上述所有问题。(这速度,想想都知道没人用)

MySQL默认设置的事务隔离级别,都是RR级别的,不过MySQL的RR级别SQL标准的RR级别不同,MySQL是可以避免幻读发生的。也就是说,MySQL里执行的事务,默认情况下不会发生脏写、脏读、不可重复读和幻读的问题。@Transactional(isolation=Isolation.DEFAULT),其实默认的就是DEFAULT值,这个就是MySQL默认支持什么隔离级别就是什么隔离级别。

MVCC

MVCC,全称Multi-Version Concurrency Control,即多版本并发控制。MVCC是一种并发控制的方法,在InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。也就是说脏写、脏读、不可重复读、幻读,都不会发生,每个事务执行的时候,跟别的事务压根儿就没关系,甭管你别的事务怎么更新和插入,我查到的值都是不变的,是一致的!可能说比较抽象,那在讲mvcc之前,不得不提一下undolog版本链这个东西了。

undolog版本链

简单来说,其实我们的每条数据都有两个隐藏字段:一个是trx_id,一个是roll_pointer。这个trx_id就是最近一次更新这条数据的事务id,roll_pointer就是指向你了你更新这个事务之前生成的undo log文件。多个事务执行的时候,每个人修改了一行数据,都会更新隐藏字段txr_id和roll_pointer,多个数据快照对应的undo log,会通过roll_pinter指针串联起来,形成一个重要的版本链!下面演示下它的原理:

  1. 比如现在有一个事务A(id=10),插入了一条数据。入的值是A,因为事务id=10,所以trxid=10;roll_pointer指向一个空的undo log,因为之前这条数据是没有的。

  2. 此时事务B(id=20)跑来修改这条数据。就把值修改为B了,同时trxid=20;然后roll_pointer指向一个新undo log,里面记录了之前的值,也就是A。

  3. 然后又来了一个事务C(id=25)过来修改。那现在值就成了C,trxid=20,roll_pointer指向的undo log值为B。

readview

现在再分析下基于undo log多版本链条实现的ReadView机制,就理解MVCC多版本并发控制机制了。这个ReadView呢,简单来说,就是你执行一个事务的时候给你生成一个ReadView,里面比较关键的东西有4个:
m_ids,这个就是说此时有哪些事务在MySQL里执行还没提交的
min_trx_id,就是m_ids里最小的值
max_trx_id,这是说mysql下一个要生成的事务id,就是最大事务id。max_trx_id并不是m_ids中的最大值。
creator_trx_id,就是你这个事务的id

读写并发

mysql的mvcc处理读写并发,正是基于undo log多版本链条+ReadView机制实现的。ReadView默认是RR级别的,现在模拟下它的流程:

  1. 假设原来数据库里存在着一行数据,他的值就是初始值,事务id是100

  2. 然后两个事务并发过来执行了,一个是事务A(id=200)过来查询的,一个是事务B(id=300)过来修改的

  3. 现在事务A开启了一个ReadView,此时m_ids包含事务A和事务B的两个id,min_trx_id就是200,max_trx_id就是301,creator_trx_id是自己。事务A第一次查询这个数据会判断,当前数据的txr_id是否小于m_ids的最小id,发现100<200,则说明这个数据是在A开启事务之前就存在的,所以能读的到这个值。

  4. B开始修改了,然后这行数据的txr_id就成了自己的id、也就是300,然后提交事务。

  5. 这个时候A又来查询了,发现数据行txr_id是300,要大于m_ids的最小值200,那么说明更新数据的事务是和自己一起或者之后开启的,所以这个修改后的值是查不到的,接着它会roll_pointer顺着undo log日志链条一直往下找,直到找到trx_id是100,100是小于200的,说明这个undo log版本必然是在事务A开启之前就执行且提交的。那么就读到了这个数据。

而RC隔离级别,实际上意思就是说你事务运行期间,只要别的事务修改数据还提交了,你就是可以读到人家修改的数据的,所以是会发生不可重复读的问题,包括幻读的问题,都会有的。就是因为他每次发起查询,都重新生成一个ReadView。

如果被问到MVCC相关现事务的原理,你不妨这么回答:

回答思路:

1、先谈mysql架构
2、引出并发的场景以及事物的影响
3、为了解决并发引出MVCC
4、MVCC的具体实现原理

Mysql的逻辑架构大概分为四层:

第一层: 服务层(为客户端服务)

为请求做连接处理,授权认证,安全等。

第二层:核心服务

比如查询解析,优化,缓存,内置函数。存储过程,触发器,视图等。对于第二层来说,所以跨存储引擎的功能都在这一层实现。

第三层:存储引擎

负责mysql中数据的存储和提取。服务器通过api与存储引擎通信,这些接口屏蔽了存储引擎之间的差异。也就是说,接口的存在,导致不同存储引擎的差异不会影响到上层查询过程。
架构分层之后,可以更好的理解一些问题,比如我们很关心的并发问题:mysql层面的并发控制,实际上是分为两种:

服务层的并发
存储引擎层的并发的

第四层:系统文件层,保存数据、索引、日志等。

事务隔离级别

大家都知道数据库事务具备ACID特性,即Atomicity(原子性) Consistency(一致性), Isolation(隔离性), Durability(持久性)

原子性:要执行的事务是一个独立的操作单元,要么全部执行,要么全部不执行
一致性:事务的一致性是指事务的执行不能破坏数据库的一致性,一致性也称为完整性。一个事务在执行后,数据库必须从一个一致性状态转变为另一个一致性状态。
隔离性:多个事务并发执行时,一个事务的执行不应影响其他事务的执行,SQL92规范中对隔离性定义了不同的隔离级别:
读未提交(READ UNCOMMITED)->读已提交(READ COMMITTED)->可重复读(REPEATABLE READ)->序列化(SERIALIZABLE)。隔离级别依次增强,但是导致的问题是并发能力的减弱。

MVCC实现

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

参考:

  • https://blog.csdn.net/wolf_love666/article/details/93634727

  • https://www.cnblogs.com/wlwl/p/14421805.html

  • https://www.jianshu.com/p/f692d4f8a53e

BAT等大厂Java面试经验总结


 

 

想获取 Java大厂面试题学习资料

扫下方二维码回复「BAT」就好了

回复 【加群】获取github掘金交流群
回复 【电子书】获取2020电子书教程
回复 【C】获取全套C语言学习知识手册
回复 【Java】获取java相关的视频教程和资料
回复 【爬虫】获取SpringCloud相关多的学习资料
回复 【Python】即可获得Python基础到进阶的学习教程
回复 【idea破解】即可获得intellij idea相关的破解教程
关注我gitHub掘金,每天发掘一篇好项目,学习技术不迷路!


回复 【idea激活】即可获得idea的激活方式

回复 【Java】获取java相关的视频教程和资料

回复 【SpringCloud】获取SpringCloud相关多的学习资料

回复 【python】获取全套0基础Python知识手册

回复 【2020】获取2020java相关面试题教程

回复 【加群】即可加入终端研发部相关的技术交流群

阅读更多

为什么HTTPS是安全的

因为BitMap,白白搭进去8台服务器...

《某厂内部SQL大全 》.PDF

字节跳动一面:i++ 是线程安全的吗?

大家好,欢迎加我微信,很高兴认识你!

在华为鸿蒙 OS 上尝鲜,我的第一个“hello world”,起飞!

相信自己,没有做不到的,只有想不到的

在这里获得的不仅仅是技术!


如果喜欢就给个“在看

mysql理论:脏读不可重复读幻读(代码片段)

文章目录1.脏读(dirtyread)脏读是指事务读取到其他事务未提交的数据2.不可重复读(non-repeatableread)不可重复读是指在同一次事务中前后查询不一致的问题3.幻读(phantomread)幻读是一次事务中前后数据量发生变化,用户产生不可预... 查看详情

什么是脏读不可重复读幻读?一文带你搞定mysql事务隔离级别(代码片段)

文章目录什么是脏读、不可重复读、幻读?一文带你搞定MySQL事务隔离级别事务ACID四个特性原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability)事务隔离级别多个事务并发执行时引发的问题脏读不可重复读幻读MySQL... 查看详情

什么是脏读不可重复读幻读?一文带你快速搞定mysql事务隔离级别(代码片段)

文章目录什么是脏读、不可重复读、幻读?一文带你快速搞定MySQL事务隔离级别事务ACID四个特性原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability)事务隔离级别多个事务并发执行时引发的问题脏读不可重复读幻... 查看详情

脏读不可重复读幻读

脏读(DirtyRead)    脏读意味着一个事务读取了另一个事务未提交的数据,而这个数据是有可能回滚  不可重复读(UnrepeatableRead)     不可重复读意味着,在数据库访问中,一个事务范围内两个... 查看详情

脏读不可重复读幻读

脏读:一个事务读取到了另外一个事务没有提交的数据         事务1:更新一条数据                  &nbs 查看详情

mysql锁与脏读不可重复读幻读详解(代码片段)

最近,在一次mysql死锁的生产事故中,我发现,关于mysql的锁、事务等等,我所知道的东西太碎了,所以,我试着用几个例子将它们串起来。具体做法就是通过不断地问问题、回答问题,再加上“适当”... 查看详情

脏读不可重复读幻读

 1.脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。2.不可重复读:是指在一个事务内,多次读同一数据... 查看详情

数据库事务隔离级别--脏读幻读不可重复读

...peatableread 、Serializable ,这四个级别可以逐个解决脏读 、不可重复读 、幻读 这几类问题。√:可能出现    ×:不会出现&nbs 查看详情

关于脏读幻读和不可重复读

1.脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。 e.g.        1.Mary的原工资... 查看详情

何为脏读不可重复读幻读(代码片段)

2.0前言事务的隔离性是指多个事务并发执行的时候相互之间不受到彼此的干扰的特性,隔离性是事务ACID特性中的I,根据隔离程度从低到高分为ReadUncommitted(读未提交),ReadCommitted(读已提交),RepeatableRead(可重复读),Seriali... 查看详情

数据库的脏读幻读不可重复读

1.脏读:指一个事务A正在访问数据,并且对该数据进行了修改,但是这种修改还没有提交到数据库中(也可能因为某些原因Rollback了)。这时候另外一个事务B也访问这个数据,然后使用了这个被A修改的数据,那么这个数据就是... 查看详情

数据库赃读不可重复读幻读

这些是事务并发产生的问题。事务隔离五种级别:      TRANSACTION_NONE 不使用事务。      TRANSACTION_READ_UNCOMMITTED 允许脏读。      TRA 查看详情

图解mvcc机制

参考技术A这个过程实际上会涉及到脏写、脏读、不可重复读、幻读,四种问题。MySQL默认的事务隔离级别是RR(可重复读),而且MySQL的RR级别是可以避免幻读发生。也就是说,MySQL里执行的事务,默认情况下不会发生脏写、脏读... 查看详情

数据库脏读不可重读读幻读

脏读:脏读是读到了别的事务回滚前的脏数据。比如事务B执行过程中修改了数据X,在未提交前,事务A读取了X,而事务B却回滚了,这样事务A就形成了脏读。也就是说,当前事务读到的数据是别的事务想要修改成为的但是没有修... 查看详情

mysql性能调优08_事务及其acid属性脏读不可重复读幻读隔离级别行锁表锁读锁写锁间隙锁临键锁(代码片段)

文章目录①.事务及其ACID属性②.脏读、不可重复读、幻读③.隔离级别④.锁分类表索、行锁、读锁、写锁⑤.表锁⑥.行锁⑦.间隙锁(GapLock)⑧.临键锁(Next-keyLocks)①.事务及其ACID属性事务:一个或一组sql语句组成一个执行单元,这个执... 查看详情

数据库并发事务存在的三个问题(脏读不可重复读幻读)

如果不考虑事务隔离性,可能会发生以下情况脏读:事务a,读到了事务b未提交的数据,如果事务a读到了事务b的一些中间数据,待处理的数据。b事务数据还没有提交,就被a事务访问了(解决方法:将读未提交级别提高到读已提... 查看详情

数据库并发导致的脏读不可重复读幻读的处理方法

在做ERP订单接入仓库库存的时候出现了一个问题。下单会读取该商品是否有库存。如果有那么就下单减去(可下单库存,物理库存不变)没有则提示库存不足在并发情况下就会导致u1用户下单编号为1的商品1个 u2用户也下单编号为... 查看详情

快速理解脏读,不可重复读,幻读(代码片段)

...几个问题。√为会发生,×为不会发生:隔离级别脏读不可重复读幻读readuncomm 查看详情