mysql高级篇——事务的隔离级别与简单应用(代码片段)

张起灵-小哥 张起灵-小哥     2022-11-30     549

关键词:

文章目录:

1.数据并发所存在的问题

1.1 脏写

1.2 脏读

1.3 不可重复读

1.4 幻读

2.SQL中事务的隔离级别

3.案例实操

3.1 查看与修改MySQL的隔离级别

3.2 读未提交-举例

3.3 读已提交-举例

3.4 可重复读-举例

3.5 幻读-举例


1.数据并发所存在的问题

针对事务的隔离性和并发性,我们怎么做取舍呢?先看一下访问相同数据的事务在 不保证串行执行 (也就是执行完一个再执行另一个)的情况下可能会出现哪些问题:

1.1 脏写

对于两个事务 Session A Session B ,如果事务 Session A 修改了 另一个 未提交 事务 Session B 修改过 的数据,那就意味着发生了 脏写。

1.2 脏读

对于两个事务 Session A Session B Session A 读取 了已经被 Session B 更新 但还 没有被提交 的字段。之后若 Session B 回滚 Session A 读取 的内容就是 临时且无效 的。 Session A Session B 各开启了一个事务, Session B 中的事务先将 studentno 列为 1 的记录的 name 列更新为' 张三 ' ,然后 Session A 中的事务再去查询这条 studentno 1 的记录,如果读到列 name 的值为 ' 张三 ' ,而Session B中的事务稍后进行了回滚,那么 Session A 中的事务相当于读到了一个不存在的数据,这种现象就称之为 脏读

1.3 不可重复读

对于两个事务 Session A Session B Session A 读取 了一个字段,然后 Session B 更新 了该字段。 之后 Session A 再次读取 同一个字段, 值就不同 了。那就意味着发生了不可重复读。 我们在 Session B 中提交了几个 隐式事务 (注意是隐式事务,意味着语句结束事务就提交了),这些事务都修改了studentno 列为 1 的记录的列 name 的值,每次事务提交之后,如果 Session A 中的事务都可以查看到最新的值,这种现象也被称之为 不可重复读

1.4 幻读

对于两个事务 Session A Session B, Session A 从一个表中 读取 了一个字段 , 然后 Session B 在该表中 插入 了一些新的行。 之后 , 如果 Session A 再次读取 同一个表 , 就会多出几行。那就意味着发生了幻读。 Session A 中的事务先根据条件 studentno > 0 这个条件查询表 student ,得到了 name 列值为 ' 张三 ' 的记录;之后Session B 中提交了一个 隐式事务 ,该事务向表 student 中插入了一条新记录;之后 Session A 中的事务再根据相同的条件 studentno > 0 查询表 student ,得到的结果集中包含 Session B 中的事务新插入的那条记 录,这种现象也被称之为 幻读 。我们把新插入的那些记录称之为 幻影记录

2.SQL中事务的隔离级别

MySQL 是一个 客户端/服务器 架构的软件,对于同一个服务器来说,可以有若干个客户端与之连接,每个客户端与服务器连接上之后,就可以称为一个会话( Session )。每个客户端都可以在自己的会话中向服务器发出请求语句,一个请求语句可能是某个事务的一部分,也就是对于服务器来说可能同时处理多个事务。事务有 隔离性 的特性,理论上在某个事务 对某个数据进行访问 时,其他事务应该进行 排队 ,当该事务提交之后,其他事务才可以继续访问这个数据。但是这样对 性能影响太大 ,我们既想保持事务的隔离性,又想让服务器在处理访问同一数据的多个事务时 性能尽量高些 ,那就看二者如何权衡取舍了。
上面介绍了几种并发事务执行过程中可能遇到的一些问题,这些问题有轻重缓急之分,我们给这些问题按照严重性来排一下序:
脏写 > 脏读 > 不可重复读 > 幻读
我们愿意舍弃一部分隔离性来换取一部分性能在这里就体现在:设立一些隔离级别,隔离级别越低,并发问题发生的就越多。 SQL 标准 中设立了 4 隔离级别 READ UNCOMMITTED :读未提交,在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。不能避免脏读、不可重复读、幻读。 READ COMMITTED :读已提交,它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这是大多数数据库系统的默认隔离级别(Oracle 默认的)。可以避免脏读,但不可重复读、幻读问题仍然存在。 REPEATABLE READ :可重复读,事务 A 在读到一条数据之后,此时事务 B 对该数据进行了修改并提交,那么事务A 再读该数据,读到的还是原来的内容。可以避免脏读、不可重复读,但幻读问题仍然存在。这是MySQL 的默认隔离级别。 SERIALIZABLE :可串行化,确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作。所有的并发问题都可以避免,但性能十分低下。能避免脏读、不可重复读和幻读。 SQL标准 中规定,针对不同的隔离级别,并发事务可以发生不同严重程度的问题,具体情况如下:

不同的隔离级别有不同的现象,并有不同的锁和并发机制,隔离级别越高,数据库的并发性能就越差, 4种事务隔离级别与并发性能的关系如下:


3.案例实操

3.1 查看与修改MySQL的隔离级别

查看MySQL的默认隔离级别,为REPEATABLE READ。

关于如何设置数据库的隔离级别,参考如下代码:👇👇👇 

SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL 隔离级别; 
#其中,隔离级别格式: 
> READ UNCOMMITTED 
> READ COMMITTED 
> REPEATABLE READ 
> SERIALIZABLE

#或者(推荐下面这种)

SET [GLOBAL|SESSION] TRANSACTION_ISOLATION = '隔离级别' 
#其中,隔离级别格式: 
> READ-UNCOMMITTED 
> READ-COMMITTED 
> REPEATABLE-READ 
> SERIALIZABLE

下面,我们建表,用作下面的案例测试。 

3.2 读未提交-举例

首先我们开启两个连接(这里均在Linux下演示),这两个连接中都将MySQL的隔离级别修改为读未提交。

此时,我们来了一个需求,需要将张三账户中的100元钱转账给李四,下面这样做:👇👇👇  我们在第一个连接中完成,首先begin显式的开启一个事务,两次update之后select可以看到转账成功了。但是此时第一个连接关于这个事务还没有进行commit提交。

上面在第一个连接中看到转账成功了,下面我们到第二个连接中看一下结果。

这里居然惊讶的看到了转账之后的数据(张三0、李四100),但是第一个连接还没有提交啊。。。

也即:在读未提交这种隔离级别下,所有事务都可以看到其他未提交事务的执行结果。

之后假如说李四这100元钱他不想要了,想再转给张三,那么我们需要在第二个连接中进行相应的update操作,但是一执行发现卡在这里了。(并不是因为数据库服务器连接问题,而是第一个连接中的那个事务还没有commit提交,所以这里需要等待第一个连接提交之后才可以继续进行DML操作)

但我此时不进行提交,我直接在第一个连接中进行rollback回滚,回滚也就意味着事务结束了。 (回滚之后的select是在下面第二张图执行之后查询的)

当回滚之后,第二个连接可以继续执行了,此时将李四的100转给张三。两次update之后select,出问题啦。。。张三200,李四-100???

这其实就是因为在第一个连接中进行了rollback回滚(张三100、李四0),此时这个数据在读未提交情况下是可以被第二个连接读到的,在此基础上,两次update导致李四又被扣了100,张三又多了100,所以李四0-100 = -100  张三 100 + 100 = 200。 (也即读未提交情况下存在脏读问题)

3.3 读已提交-举例

首先将上面的account表中数据清空,仍然向表中插入与上面案例相同的两条数据(张三100、李四0),进行下面的读已提交举例。

仍然是开启两个MySQL连接做测试。

下面在两个连接中,分别设置隔离级别为 读已提交。 

下面首先在第二个连接中 begin 开启一个事务,将张三的存款扣50元,那么此时在当前连接中肯定是可以select到正确的数据(张三50、李四0)。

然后,我们到第一个连接中,也开启一个事务,(如果是读未提交了话,由于第二个连接并没有commit提交,此时第一个连接就会读取到 张三50、李四0)。

但是此时隔离级别是读已提交,还是如此嘛?(如下可以看到此时已经不会读取到另一个事务未提交的数据了,也即在读已提交的情况下,解决了脏读问题)

下面在第二个连接中,把事务提交,select查询。回到第一个连接中再次查询,数据肯定也是正确的。

3.4 可重复读-举例

此时还以上面案例的数据为基准(张三50、李四0),来做测试,先将两个连接中的隔离级别修改为可重复读。

在第一个连接中开启一个事务, 然后将张三的存款扣10元钱,当前连接肯定可以select到正确的数据。

下面在第二个连接中也开启一个事务,此时读取到50是因为第一个事务还未提交数据,那么是不能被第二个连接中的事务读取到的。

然后我们在第一个连接中将事务提交,那么第一个连接中再次读取肯定还是正确数据(张三40、李四0)。

那么在第二个连接中是怎么样的呢?它能不能读取到正确数据(张三40、李四0)?

下面的实例表明:读取到的还是和第一次一样(张三50、李四0),这就达到了可重复读的要求,也就是事务A在读到一条数据之后,此时事务B对该数据进行了修改并提交,那么事务A再读该数据,读到的还是原来的内容。

下面,我们在第二个连接中将事务提交,再次读取,此时两个连接事务均已结束,所以肯定都会读取到正确数据了(张三40、李四0)。

3.5 幻读-举例

此时还基于可重复读这种隔离级别下,演示一下幻读的情况。   先在第一个连接中开启一个事务,然后插入一条id为3的数据。

然后我们回到第二个连接中,也开启一个事务,执行如下操作。

可以看到,id为3的记录为0(也即没有这条记录),因为第一个连接中的事务还未提交,这里自然读取不到。

下面将第一个连接中的事务提交,回到第二个连接中再次读取。

通过上面在第二个连接中的执行结果来看,按理说第一个连接中的事务已经提交,这里为什么还读取不到呢?  这里其实就出现了幻读的情况。

对于两个事务Session ASession B, Session A 从一个表中 读取 了一个字段, 然后 Session B 在该表中 插入 了一些新的行。 之后, 如果 Session A 再次读取 同一个表, 就会多出几行。

我们可以在第二个连接所处的当前事务中再次插入id为3的记录。

上面的执行结果告诉我们,id为3的记录已经存在了。这也就是说在第一个连接中的那个事务已经向表中添加了这条记录、并且也已提交,所以记录必然存在了,但是在第二个连接中的事务却查询不到,但是也无法插入同id的数据,这就感觉好像出现了幻觉一样的数据。即幻读了。。。

mysql原理篇之事务隔离级别和mvcc--13(代码片段)

Mysql原理篇之事务隔离级别和MVCC--13事前准备事务隔离级别事务并发执行遇到的问题SQL标准中的四种隔离级别MySQL中支持的四种隔离级别如何设置事务的隔离级别MVCC原理版本链ReadViewREADCOMMITTED——每次读取数据前都生成一个ReadView... 查看详情

重新整理mysql基础篇—————事务隔离级别[四]

前言简单介绍一下事务隔离的基本正文ReadUncommitted(未提交读)这个就是读未提交。就是说在事务未提交的时候,其他事务也可以读取到未提交的数据。这里举一个例子,还是前一篇的例子。假如一个张表A=500,B=300,(500,300)有一个... 查看详情

再谈事务(代码片段)

上一篇咱们简单了解了事务,这一篇我们再深入一下吧Ⅰ、事务隔离级别事务一共有四种隔离级别简称全称-ruread-uncommited未提交读rcread-commited提交读rrrepeatable-read可重复读srzserializable可串行从真正意义上来看只有srz达到真正隔离性... 查看详情

《mysql高级篇》十四多版本并发控制(代码片段)

文章目录1.什么是MVCC2.快照读与当前读2.1快照读2.2当前读3.复习3.1再谈隔离级别3.2隐藏字段、UndoLog版本链4.MVCC实现原理之ReadView4.1什么是ReadView4.2设计思路4.3ReadView的规则4.4MVCC整体操作流程5.举例说明5.1READCOMMITTED隔离级别下5.2REPEAT... 查看详情

事务与mysql隔离级别(代码片段)

事务定义:比如ABCD四个业务,作为一个事务,他们要么一起都执行完毕,要么都不执行。(只要有一个不成功,那么所有的都不可以成功)四个特性ACID原子性(Atomicity)整个事务中的所有操作,要么全都完成,要么全部不完成。事务... 查看详情

mysql事务隔离级别(代码片段)

MySQL的事务必须满足A(原子性)C(一致性)I(隔离性)D(持久性)原则。其中,隔离性是为了尽量减少并发事务彼此之间的影响,最高的隔离级别可以保证并发事务之间互不影响。  在... 查看详情

mysql高级——锁与事务(代码片段)

MySQL高级(二)——锁与事务文章目录MySQL高级(二)——锁与事务一、MySQL锁机制**1.1锁与其应用场景锁的类型和适合的场景读阻塞写、写阻塞读手动锁定一行实现一个事务行锁升级为表锁的情况间隙锁的问题(范... 查看详情

mysql高级——锁与事务(代码片段)

MySQL高级(二)——锁与事务文章目录MySQL高级(二)——锁与事务一、MySQL锁机制**1.1锁与其应用场景锁的类型和适合的场景读阻塞写、写阻塞读手动锁定一行实现一个事务行锁升级为表锁的情况间隙锁的问题(范... 查看详情

面试官问:mysql锁与事物隔离级别你知道吗?(代码片段)

...法、MySQL性能优化篇一些内容。我们再来聊聊MySQL的锁与事务隔离级别,分上下两篇,本篇重点讲MySQL的行锁与事务隔离级别。锁定义锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除了传统的计算资源(... 查看详情

数据库事务的4大特性与隔离级别(代码片段)

本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别。如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性:⑴原子性(Atomicity)  原子性是指事务包含的所有操作要么全... 查看详情

mysql基础篇之事务真的是隔离的吗?--08(代码片段)

Mysql基础篇之事务真的是隔离的吗?--08引言“快照”在MVCC里是怎么工作的?更新逻辑小结引言我在第3篇文章和你讲事务隔离级别的时候提到过,如果是可重复读隔离级别,事务T启动的时候会创建一个视图read-view&... 查看详情

springboot系列教程之事务隔离级别知识点小结

SpringBoot系列教程之事务隔离级别知识点小结上一篇博文介绍了声明式事务@Transactional的简单使用姿势,最文章的最后给出了这个注解的多个属性,本文将着重放在事务隔离级别的知识点上,并通过实例演示不同的事务隔离级别下... 查看详情

mysql事务篇:acid原则事务隔离级别及事务机制原理剖析

引言众所周知,​​MySQL​​数据库的核心功能就是存储数据,通常是整个业务系统中最重要的一层,可谓是整个系统的“大本营”,因此只要​​MySQL​​存在些许隐患问题,对于整个系统而言都是致命的。那此刻不妨思考一... 查看详情

python进阶篇:mysql隔离级别详解

...复读、幻读等一系列问题。MySQL提供了一系列机制来解决事务并发问题,比如事务隔离、锁机制、MVCC多版本并发控制机制。今天来探究一下事务隔离机制。目录)前言1,什么是事务(Transacation)?2,如何满足事... 查看详情

mysql事务管理(代码片段)

文章目录CURD什么是事务为什么会出现事务事务的版本支持事务提交方式事务常见操作方式事务隔离级别理解隔离性查看与设置隔离性隔离级别读未提交【ReadUncommitted】读提交【ReadCommitted】可重复读【RepeatableRead】串行化【Serializ... 查看详情

mysql的事务隔离级别及各个隔离级别应用场景,详细

...的作用是用来平衡数据库并发访问与数据一致性的方法。事务的4种隔离级别READUNCOMMITTED   未提交读,可以读取未提交的数据。READCOMMITTED    已提交读,对于锁定读(selectwithforupdate或者forshare)、update和delet... 查看详情

mysql事务隔离级别详解

...特性:四大特性    · 原子性  事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。通常,与某个事务关联的操作具有共同的目标,并且是相互依赖的。如果系统只执行这些操... 查看详情

mysql是如何实现四大隔离级别的

...准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。ReadUncommitted(读取未提交内容)在该隔离级别,所有... 查看详情