Mysql系列(二)Mysql事务四大隔离级别详解&演示

本文主要验证下mysql的集中隔离级别下产生的问题,使用的版本是8.0.18。

四种隔离级别

Mysql的innodb引擎支持事务,默认有如下四个隔离级别,隔离程度由低到高。

  • read-uncommitted :未提交读
  • read-committed :已提交读
  • repeatable-read :可重复读
  • serializable :串行化,要求两个事务串行执行

不同的隔离级别下会产生不同的问题,脏读,不可重复读,幻读,对应关系具体如下:

脏读不可重复读幻读
未提交读
已提交读
可重复读是/否
串行化
  • 脏读 :事务B读取了事务A没有提交的数据,叫做脏读;比如AB两个事务都在操作数据库,事务A修改了一条数据值由10改为5,但是没提交事务,此时还事务B去查询,能查到这个5;如果此时事务A回滚回10,那么事务B插到的5就是脏数据,叫做脏读。
  • 不可重复读:一个事务开始后,在提交之前,多次查询同一条数据,值不相同,叫做不可重复读。比如,事务B查询一条数据值为10,还没提交事务;此时事务A修改值为5,然后事务A再次查询得到5;上一次是10,下一次是5,产生了不可重复读的问题。
  • 幻读:一个事务开始后,在提交之前,多次查询同一张表的数据,多次查询数目不一致,产生幻读;比如,事务B第一次查询表得到2条数据,此时事务A插入一条数据,然后事务B再次查询表,回得到3条数据;第一次2条,第二次变成3条,产生了幻读。

注意:之前很多博客都说repeatable-read 会产生幻读问题,但经过实际验证和查阅资料,目前mysql版本已经在repeatable-read 这个级别部分解决了幻读的问题。 为什么是部分呢?因为事务B如果只是多次查询,则不会出现幻读问题,但是当事务B中间发生了update等当前读的操作,后续再select就会发生幻读

下面针对脏读,幻读,不可重复读进行演示。

准备:

初始化一张表user,插入几条数据;
在这里插入图片描述
在查询sql的时候,sql语句末尾使用分号,这时数据库回自动提交事务,为了演示,需要关闭自动提交;
可使用如下命令查看自动提交关闭情况:
show global variables like ‘autocommit’;

使用如下命令关闭自定提交:
set autocommit=0;

然后,修改数据库默认隔离级别,innodb搜索引擎默认隔离级别是可重复读(repeatable-read),可使用如下命令查询:
select @@transaction_isolation; (对于比较老的版本是 select @@tx_isolation;)

使用如下命令修改隔离级别:
set transaction_isolation=‘read-uncommitted’;
set transaction_isolation=‘read-committed’;
set transaction_isolation=‘repeatable-read’;
set transaction_isolation=‘serializable’;

下面正式开始,先说演示脏读,

我们开两个会话窗口,左边记为事务A,右边记为事务B;整体上在事务A中做修改,B中做查询,看看B中产生的脏读,不可重复读,幻读等问题。

脏读

先设置隔离级别为未提交读read-uncommitted,
在这里插入图片描述
开始数据库表第1条数据的age值为27,在事务A中更新为17,但是事务A不提交;此时事务B去查询这条记录,得到了A没提交的17;
如果此时A回滚,或者将age改为别的值,那么B读取到的这个17就是脏数据,产生了脏读。

解决脏读
要解决脏读很简单,将隔离级别设置为已提交读即可,因为在事务B中查询验证,只要将B的隔离级别设置为read-committed:
在这里插入图片描述
此时事务A再次更新age,由17改为37,然后B去查询,得到的是更新之前的数据17,避免了脏读;
如果B要读取更新之后的数据,只能等A提交事务,也就是commit;
下面把A提交,然后B就查到了更新后的37 。
在这里插入图片描述

不可重复读

紧接着上面,虽然避免了脏读,但是我们发现,事务B在一次事务期间(因为B始终没有运行commit命令,所以一直处于同一个事务没结束),查询同一条数据,得到了多个个不同的值,比如我在A中再次更新age为47,
在这里插入图片描述
事务B一开始是37,后来再次查询,得到了47,这就是不可重复读。

解决不可重复读
要解决这种不可重复读,需要将事务隔离级别设置为可重复读 repeatable-read ,
在这里插入图片描述
我们将事务B的隔离级别设置为了可重复读,
然后事务A更新age为57,然后开启事务查询,得到57;
然后事务A更新age为67,此时B再次查询,得到的依然是57,避免了不可重复读。

幻读

查询期间 ,其他事务插入操作产生的幻读,但是innodb在可重复读隔离级别已经解决,证明如下:
在这里插入图片描述
事务B开始后,先查询到了所有的8条数据,
然后事务A插入一条新数据“冯大臣”,commit事务,
然后事务B再次查询,并没有查到新插入的数据,说名mysql的innodb引用的可重复读已经解决了幻读的问题。具体使用的是间隙锁解决,就是在事物B开始了范围查询后,mqsql就锁住了0到10之间的行数,事物A往这个范围插入数据就会失败。

那么把隔离级别改回已提交读,这个隔离级别会产生幻读,如下:(这里删除了“冯大臣”这条数据),
在这里插入图片描述
事务B开始查询到了2条数据,事务还没提交,
然后A插入一条新数据,提交事务,
然后事务B再次查询,得到了3条数据,这就是幻读。

串行化

串行化的隔离级别,要求两个事务串行执行,这里也演示下:

两个会话都要设置为’serializable’;
在这里插入图片描述
首先,事务B先开始事务,进行了范围查询,范围是id<10,
然后事务A更新id=1的数据,这时发现,跟新的动作被阻塞,这就是串行化,A必须等到B提交事务后,才能继续;

下面我们提交事务B,
然后就会发现A的更新成功了,耗时39.75s,因为中间被阻塞了。
在这里插入图片描述
本文就先验证到这里,对于mysql如何实现这几种隔离级别,也就是MVCC原理,后续在分析。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程简介: 课程总计41课时,从什么是事务讲起,直到分布式事务解决方案,很的0基础基础与提升系列课程。对于难以理解的知识点,全部用画图+实战的方式讲解。 第一部分:彻底明白事务的四个特性:原子性、一致性、隔离性、持久性,用场景和事例来讲解。 第部分:实战讲数据库事务的6中并发异常:回滚丢失、覆盖丢失、脏、幻、不可重复、MVCC精讲。 第三部分:彻底搞清楚4种事务隔离级别:READ_UNCOMMITTED 提交隔离级别、READ_COMMITTED 提交隔离级别、REPEATABLE_READ 可重复度隔离级别、SERIALIZABLE 序列化隔离级别 第四部分:彻底搞清楚MySQL的各种锁:行锁、表锁、共享锁、排它锁、Next-Key锁、间隙锁、X锁、S锁、IS锁、IX锁、死锁、索引与锁、意向锁等。 第五部分:彻底搞清楚Spring事务的7种传播级别的原理和使用:PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS、PROPAGATION_MANDATORY、PROPAGATION_REQUIRES_NEW、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER、PROPAGATION_NESTED分布式事务的理论基础:RPC定理、BASE理论、XA协议都是什么,原理是什么,有什么关联关系 第六部分:分布式事务的5种解决方案原理和优缺点:2PC两阶段提交法、3PC三阶段提交法、TCC事务补偿、异步确保策略、最大努力通知策略 第七部分:阿里巴巴分布式事务框架Seata:历经多年双十一,微服务分布式事务框架,用一个Nacos+Spring Cloud+Seta+MySql的微服务项目,实战讲解阿里的分布式事务技术,深入理解和学习Seata的AT模式、TCC模式、SAGA模式。 课程资料: 课程附带配套2个项目源码72页高清PDF课件一份阿里巴巴seata-1.1.0源码一份阿里巴巴seata-server安装包一份
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值