再有人问你MySql的隔离级别,直接把这篇文章发给他!

作者 l zyz1992

来源 l Hollis(ID:hollischuang)

首先要明白什么是事务?

事务是程序中一系列严密的操作,所有的操作必须完成,否则在所有的操作中所做的所有的更改都会被撤销。也就是事务的原子性,一个事务中的一系列的操作要么全部成功,要么就是失败。

事务的结束有两种,当事务中所有的步骤全部成功执行的时候,事务提交。如果其中一个步骤失败,将会发生回滚操作,撤销到事务开始之前的所有的操作。

 

事务的ACID

事务具有四个特征

  1. 原子性 事务是数据库的逻辑工作单位,事务中包含多个操作,要么都做完,要么都不做

  2. 隔离性(隔离性也是本文的重点) 事务彼此之间是不能互相干扰的,即一个事务的操作对该数据库的其他事务操作是隔离的,并发执行的各个事务时间互补干扰

  3. 持久性 事务一旦提交,其变更是永久性的

  4. 一致性 事务执行的结果必须满足从一个状态变到另一个状态,因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性的状态。如果数据库系统在运行时发生系统故障,有些未完成的事务被迫中止,而有一部分修改已经写入数据库,这个时候数据库就处于一种不正确的状态。

其实以上三个条件(原子性、隔离性、持久性)最终都是为了保持数据库数据的一致性服务的

MySQL的四种隔离级别

SQL标准定义了四种隔离级别,用来限定事务内外的哪些改变是可见的,哪些是不可见的。

  1. 读取未提交的数据【Read Uncommitted】 在该隔离级别,所有的事务都可以看到其他事务没有提交的执行结果。(实际生产中不可能使用这种隔离级别的)

  2. 读取提交的内容【Read Committed】 该隔离级别是大多数数据库的默认的隔离级别(不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离级别也支持不可重复读,即同一个 select 可能得到不同的结果

  3. 可重读【Repeatable Read】 这是 MySQL 默认的隔离级别,它确保同一个事务在并发读取数据时,会看到同样的数据行。不过理论上会导致另外一个问题,【幻读】。幻读:相同的条件查询一些数据,然后其他事务【新增】或者是【删除】了该条件的数据,然后导致读取的结果不一样多。InnoDB 存储引擎通过多版本控制(MVCC)机制解决了该问题

  4. 可串行化【serializable】 这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决了幻读的问题。它在每个读的数据行上面加上共享锁,。但是可能会导致超时和锁竞争(这种隔离级别太极端,实际生产基本不使用)

这四种隔离级别采用不同的锁类型来实现

  1. 脏读 读取了前一个事务未提交的或者是回滚的数据

  2. 不可重复度 同样的 select 查询,但是结果不同,过程中有事务更新了原有的数据

  3. 幻读 两次查询的结果数量不一样,过程中有事务新增或者是删除数据

下面对不同的隔离级别产生的不同的问题做一个汇总

各个隔离级别的详细测

查看数据库的隔离级别

show variables like '%isolation%'

设置数据库的隔离级别

set session transaction isolation level Read Uncommitted;

设置数据库的隔离级别为:Read Uncommitted

实验一:Read Uncommitted

Read Uncommitted 即:读取未提交

前置条件:将数据库的隔离级别设置为read uncomitted;

set session transaction isolation level Read Uncommitted;

img

img

第一步:A开启事务:start tracsaction;

img

第二步:A查询数据:select * from test;

img

第三步:B开启事务:start transaction;

img

第四步:B查询数据:select * from test;

img

第五步:B更新数据:update test set num =10 where id = 1;B没有提交事务

img

第六步:A读取数据----A读取到了B未提交的数据(当前数据库的隔离级别是:Read Uncommitted

img

第七步:B回滚数据:rollback;

img

第八步:B查询数据:select * from test;

img

第九步:A查询数:select * from test;

img

结论:事务B更新了数据,但是没有提交,事务A读取到的是B未提交的记录。因为造成脏读。Read Uncommitted是最低的隔离级别

实验二:读取已提交-Read Committed

前置条件:将数据库的隔离级别设置为:Read Committed;

set session transaction isolaction level Read Committed;

img

img

第一步:A开始事务:start transaction;

img

第二步:A查询数据:select *from test;

img

第三步:B开启事务:start transaction;

img

第四步:B查询数据:select * from test;

img

第五步:B更新数据:update test set num =10 where id=1

查看结果:

img

第六步:A查询数据:select * from test;

img

第七步:B提交数据:commit;

img

第八步:A查询数据:select * from test;

img

结论:Read Committed 读已提交的隔离级别解决了脏读的问题,但是出现了不可重复读的问题,即事务A在两次查询的结果不一致,因为在两次查询之间事务B更新了一条数据。

读已提交的只允许读取已经提交的记录 ,但是不要求可重复读

实验三:可重读度-Repeatable Read

前置条件:将数据库的级别设置为可重复度

set session transaction isolation level repeatable read;

img

第一步:A开始事务:start transaction;

img

第二步:A查询数据:select * from test;

img

第三步:B开启事务:start transaction;

img

第四步:B查询数据:select * from test;

img

第五步:B更新数据:update test set num=10 where id=1;

img

此时B并没有提交事务

第六步:B查询数据:select * from test;

img

第七步:A查询数据

img

结果仍然是之前的结果(因为B事务还没有提交)

第八步:B提交事务:commit;

img

第九步:A查询数据:select * from test;此时A查询的记录仍然和之前一样

img

第十步:B插入一条数据并提交事务:inset into test(num) value(4);

img

第十一步:A查询数据,发现结果还是和之前的一样:select * from test;

img

第十二步:A提交事务并查询数据

img

此时发现A查询的数据已经和B查询的结果一致了;

结论:Repeatable Read隔离级别只允许读取已经提交的事务的记录,

实验四:串行化-Serializable

前置条件:将数据库的隔离级别设置为可串行化

img

第一步:A开始事务并查询数据

img

第二步:B开启事务并insert数据,发现只能等待,并不能执行下去

img

第三步:A提交事务

img

第四步:B插入数据

img

结论:serializable完全锁定字段,若一个事务来操作同一份数据,那么就必须等待,直到前一个事务完成并解除锁为止。是完整的隔离级别,会锁住对应的数据表,因为会导致效率问题。

本文小结

本片文章并没有深入的去讲解原理,而是让大家能够从更直观的从隔离级别的表面去了解隔离级别,因为我发现我的很多同事对此是模模糊糊,模棱两可的,但是这个是不可以的,因为技术本身是不允许存在这种歧义的,懂就是懂,才能合理运用,如果模棱两可,那么在实际运用中一定也是漏洞百出,所以这也是这篇文章诞生的原因。

我们可以先抛开原理与底层的具体实现,先能够清晰且明了的搞清楚各个专业术语的含义,这未尝不是一种进步。

最后以一句不积跬步无以至千里,不积小流无以成江河与诸君共勉!


往期推荐

厉害了,Spring中bean的12种定义方法!


@Autowired报错的4种解决方案和原因分析!


SpringBoot 中的 3 种条件装配!



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544696.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring与Hibernate两种组合方式

Spring与Hibernate大致有两种组合方式,主要区别是一种是在Hibernate中的hibernate.cfg.xml中配置数据源,一种是借助Spring的jdbc方式在Spring的applicationContext.xml文件中配置数据源,然后在Spring配置sessionFactory的bean有些区别 下面大致的说明一下…

Java CharArrayReader mark()方法与示例

CharArrayReader类mark()方法 (CharArrayReader Class mark() method) mark() method is available in java.io package. mark()方法在java.io包中可用。 mark() method is used to mark the current position in the stream and whenever the call to reset() method so it re…

C# Winform 窗体美化(五、鼠标穿透)

五、鼠标穿透 以前在玩射击游戏的时候,狙击枪的设定一般是开镜才有准星,所以想是不是可以自己造一个默认准星出来,思路是现在窗口上画一个准星,然后把窗体其他区域都透明,然后设置鼠标穿透; 结果是&#…

生产环境一次诡异的NPE问题,反转了4次

前言公司为了保证系统的稳定性,加了很多监控,比如:接口响应时间、cpu使用率、内存使用率、错误日志等等。如果系统出现异常情况,会邮件通知相关人员,以便于大家能在第一时间解决隐藏的系统问题。此外,我们这…

ZooKeeper学习笔记—配置管理

为什么80%的码农都做不了架构师?>>> 最近在工作中,为了完善公司集群服务的架构,提高可用性,降低运维成本,因此开始学习ZooKeeper。 至于什么是ZooKeeper?它能做什么?如何安装ZooKee…

Java BigDecimal compareTo()方法与示例

BigDecimal类compareTo()方法 (BigDecimal Class compareTo() method) compareTo() method is available in java.math package. compareTo()方法在java.math包中可用。 compareTo() method is used to compare this BigDecimal object to the given object or in other words …

C# Winform 窗体美化(六、双层窗体)

六、双层窗体 大概情况 双层床体是为了平滑的创建异形窗体的一个解决方案,找了很多资料,整理了一下。 双层窗体的逻辑是建立在 UpdateLayeredWindow 不能绘制控件的基础上,上层再添加一个专门放置控件的层;这样就可以在上层“控…

批处理框架 Spring Batch 这么强,你会用吗?

来源:blog.csdn.net/topdeveloperr/article/details/84337956spring batch简介Spring Batch架构介绍Spring Batch核心概念介绍chunk 处理流程批处理操作指南spring batch简介 spring batch是spring提供的一个数据处理框架。企业域中的许多应用程序需要批量处理才能在…

Android Bundle类别

即使在今天发现自己Bundle类不明确,因此,花时间去研究了一下。 依据google官方文件(http://developer.android.com/reference/android/os/Bundle.html) Bundle类是一个key-value对,“A mapping from String values to …

C# Winform 窗体美化(七、Win7 Aero 毛玻璃效果)

七、Win7 Aero 毛玻璃效果 在 Win7 上有一种 Aero 效果,毛玻璃透明效果,搭配不同风格的颜色,效果很好。在学习 Winform 美化的时候顺便看到的这种效果,也整理进来了。 注意:Win7 上想看到这种效果需要开启并使用 Aer…

非导向传输媒体| 计算机网络

Transmission media can be categorized in two ways, 传输媒体可以通过两种方式进行分类: Guided Transmission Media 引导传输媒体 Unguided Transmission Media 非引导传输媒体 1)非引导传输媒体 (1) Unguided Transmission Media) It is also called wireless …

面霸篇:MQ 的 5 大关键问题详解

最近mq越来越火,很多公司在用,很多人在用,其重要性不言而喻。但是如果我让你回答下面的这些问题:我们为什么要用mq?引入mq会多哪些问题?如何解决这些问题?你心中是否有答案了呢?本文…

C# Winform 窗体美化(八、Icon)

八、Icon 之前 Winform 项目也有在 Icon 上遇到些问题(这里的 Icon 指的是 .ico 类型的文件),比如刚开始不知道怎么让自己的程序 Icon 和其他软件一样可以放大,还有放大之后在音量合成器中会出现比较奇葩的效果之类的问题&#x…

Java LocalDate类| 带示例的getEra()方法

LocalDate类的getEra()方法 (LocalDate Class getEra() method) getEra() method is available in java.time package. getEra()方法在java.time包中可用。 getEra() method is used to get the era applicable for this LocalDate object. getEra()方法用于获取适用于此LocalD…

MyBatis 的执行流程,学废了!

作者:双子孤狼来源:blog.csdn.net/zwx900102/article/details/108455514MyBatis可能很多人都一直在用,但是MyBatis的SQL执行流程可能并不是所有人都清楚了,那么既然进来了,通读本文你将收获如下:1、Mapper接…

C# Winform 窗体美化(九、嵌入窗体)

九、嵌入窗体 还是关于 Winform 窗体的一些操作问题,这次是研究了一个嵌入窗体,这次学习纯属偶然,项目中确实没遇到过这种需求。就是把别人的程序嵌入到自己的程序中,就像这样: 这里我嵌入了测试显示器的程序 [外链图…

Mac 流程图

https://www.lucidchart.com/pages/signup?utm_expid39895073-174.qKyHpBEbQS26y86OArD-rQ.1 https://www.processon.com/

setname_Python线程类| setName()方法与示例

setnamePython Thread.setName()方法 (Python Thread.setName() Method) Thread.setName() method is an inbuilt method of the Thread class of the threading module in Python. It uses a Thread object and sets the name of the thread. Thread.setName()方法是Python中线…

SpringBoot 优雅的参数效验!

引言 不知道大家平时的业务开发过程中 controller 层的参数校验都是怎么写的?是否也存在下面这样的直接判断?public String add(UserVO userVO) {if(userVO.getAge() null){return "年龄不能为空";}if(userVO.getAge() > 120){return &quo…

NTFS Change Journal(USN Journal)详解

写在前面 最近又用了一下usn日志来获取所有文件列表,在分多次加载文件列表的时候发现有文件丢失的情况,后来发现一篇文章比较详细的讲了usn。 用cmd来读取usn日志 如图: 以下是转载内容: 还是那个文件监控的应用,…