mysql 开启不记录事务_你还不知道吧?MySQL事务隔离级别原来这么简单

本文详细介绍了数据库事务的ACID特性,并重点讲解了MySQL的四种事务隔离级别:Read Uncommitted、Read Committed、Repeatable Read和Serializable。通过实例展示了不同隔离级别下可能出现的脏读、不可重复读和幻读问题。最后总结了各隔离级别的特点及其在实际应用中的选择。
摘要由CSDN通过智能技术生成
●MySQL事务隔离级别(1)●第1节:

事务概述

第2节:

MySQL4种事务隔离级别分析

第3节:

总结

877500290b71079f45aa0a1a079b5e97.png

1  事务概述

260c9e9675484c32771f98a9dffb24c2.png5c54310ca48c89e999771b5c53cda3cb.png

什么是事务?

数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。事务的使用是数据库管理系统区别文件系统的重要特征之一。

事务拥有四个重要的特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability),人们习惯称之为 ACID 特性。

65eb58a407033330b8acf59371dfd6b3.png a819335f160ad856c1ce0e3b9ea3cf74.png

事务

特性

事务具有ACID特性

1. 原子性(Atomicity)。事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。例如,如果一个事务需要新增 100 条记录,但是在新增了 10 条记录之后就失败了,那么数据库将回滚对这 10 条新增的记录。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。

2. 一致性(Consistency)。指事务将数据库从一种状态转变为另一种一致的的状态。事务开始前和结束后,数据库的完整性约束没有被破坏。例如工号带有唯一属性,如果经过一个修改工号的事务后,工号变的非唯一了,则表明一致性遭到了破坏。

3. 隔离性(Isolation)。要求每个读写事务的对象对其他事务的操作对象能互相分离,即该事务提交前对其他事务不可见。也可以理解为多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果。这指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。例如一个用户在更新自己的个人信息的同时,是不能看到系统管理员也在更新该用户的个人信息(此时更新事务还未提交)。

4. 持续性(Durability)。事务一旦提交,则其结果就是永久性的。即使发生宕机的故障,数据库也能将数据恢复,也就是说事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。这只是从事务本身的角度来保证,排除 RDBMS(关系型数据库管理系统,例如 Oracle、MySQL 等)本身发生的故障。

877500290b71079f45aa0a1a079b5e97.png

2  MySQL4种事务隔离级别分析

隔离

级别

事务隔离级别概述

SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。

1. Read Uncommitted(读取未提交内容)。在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。

2. Read Committed(读取提交内容)。

这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

3. Repeatable Read(可重读)。

这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

4. Serializable(可串行化)。

这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

以上这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如:

  • 脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。

  • 不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新了原有的数据。

  • 幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。

MySQL数据库实现了这以上4种隔离级别,每种隔离级别可能会产生的问题如下表所示:

隔离级别

脏读

不可重复读

幻读

Read Uncommitted

Y

Y

Y

Read Committed

N

Y

Y

Repeatable Read

N

N

Y

Serializable

N

N

N

隔离

级别

测试各种隔离级别

创建一张Student表。

CREATE TABLE `student` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(64) NOT NULL,  `age` int(4) NOT NULL,  `gender` varchar(8) NOT NULL,  `createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,  `updateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8

分别使用2个客户端A和B操作Student表,不断修改客户端A的隔离级别,在客户端B进行数据修改。

                    01 客户端A将隔离级别设置为Read Uncommitted                        

客户端A:将隔离级别调整为Read Uncommitted,然后查询当前隔离级别如下图所示。

bc2bf895f0a8870ba9ec45ea330cea5e.png

客户端A:开启一个事务,此时数据为初始状态。

232228eaa68a8554ff17c0aaf111b244.png

客户端B:启动一个事务,更新id=1学生,将其name属性修改为wushuang,但不提交事务。

1a93b2f5239a5ac9b62f35586bc0d3e8.png

客户端A:再次读取数据,发现数据已经被修改了,这就是所谓的“脏读”。

aaae177780015052ad3f72e183726ebc.png

客户端B:事务回滚。回滚后的id=1的学生name属性仍然为zhangsan。

4f0d53dcb38ab10e3d99fe55b55cfcff.png

客户端A:再次读取Student表中的数据,发现id=1的学生name属性仍然为zhangsan。

26de25bed633e04ee2fb5ebef73ba491.png

经过上面的实验可以得出结论,事务B更新了一条记录,但是没有提交,此时事务A可以查询出未提交记录。造成脏读现象。未提交读是最低的隔离级别。

                    02 客户端A将隔离级别设置为Read Committed                        

客户端A:将隔离级别调整为Read Committed,然后查询当前隔离级别。

a994132611b3284aff5417cdde99d4b1.png

客户端A:开启一个事务,此时数据为初始状态。

19028b8c67e28a0106335d2063c1ba6e.png

客户端B:启动一个事务,更新id=1学生,将其name属性修改为wushuang,但不提交事务。

3361860c661d23b820dbd9edb357dda6.png

客户端A:再次读取数据,发现数据未被修改。

25578e86d098b0e1d5e9531832be7c02.png

客户端B:事务提交。

e969c6026fd04bd5822f38bb664fe148.png

客户端A:再次读取Student表中的数据,发现id=1的学生name属性为wushuang。

6a0d5e59f255e389f1a3c37675837d96.png

经过上面的实验可以得出结论,已提交读隔离级别解决了脏读的问题,但是出现了不可重复读的问题,即事务A在两次查询的数据不一致,因为在两次查询之间事务B更新了一条数据。已提交读只允许读取已提交的记录,但不要求可重复读。

                    03 客户端A将隔离级别设置为Repeatable Read                        

客户端A:将隔离级别调整为Repeatable,然后查询当前隔离级别。

3a1ed855478fd5139c87c79af47f2551.png

客户端A:开启一个事务,此时数据为初始状态。

92f4ede608808707470777384cfdd947.png

客户端B:启动一个事务,更新id=1学生,将其name属性修改为无双,但不提交事务。

6e02232f9c4373ebf9a74e4832aa2ada.png

客户端A:再次读取数据,发现数据未被修改。

995a07e0855b8537b8f95e9d78f7fc82.png

客户端B:事务提交。

120ca4cf21c88672377b9d6ae70ff241.png

客户端A:再次读取数据,发现数据未被修改。

995a07e0855b8537b8f95e9d78f7fc82.png

客户端B:插入一条新的数据,并提交。

41b6846ec0cfa2a62c6a6d9d9f98a8ef.png

客户端A:再次读取Student表中的数据,发现数据未被修改。

995a07e0855b8537b8f95e9d78f7fc82.png

客户端A:提交事务。再次读取Student表中的数据,发现多了一条数据wangwu

3a0a3c3ccd185a69a99583bfd85f927f.png

由以上的实验可以得出结论,可重复读隔离级别只允许读取已提交记录,而且在一个事务两次读取一个记录期间,其他事务不得更新该记录。但该事务不要求与其他事务可串行化。例如,当一个事务可以找到由一个已提交事务更新的记录,但是可能产生幻读问题(注意是可能,因为数据库对隔离级别的实现有所差别)。像以上的实验,就没有出现数据幻读的问题。

重新执行以上步骤,分别开启客户端A和客户端B,事务隔离级别依旧保持为repeatable read。在客户端B插入一条数据。

7de8dafad86a5e95256dc9cf3b64e10d.png

客户端A插入一条id=4的学生数据。

fc8a97b30b61e555625a93ed971f39ed.png

客户端A出现主键冲突问题。其实这就是该隔离级别下可能产生的问题,MySQL称之为幻读。 

                    04 客户端A将隔离级别设置Serializable                        

客户端A:将隔离级别调整为Serializable,然后查询当前隔离级别。

fd1272d26532603e8a420d209d9cd584.png

客户端B:启动一个事务,插入一个name=xiaoming的同学。

6c32ee65e26e7f65353993909193b208.png

由于客户端A事务并未提交,因此客户端B的insert语句将会阻塞。

客户端A:提交事务。

cb9fb4fefd91b38801cb086f6499ffc4.png

客户端B:在客户端A提交后,客户端B的insert语句执行结束。

a06b92a1f80ac30477c00fae39c725c7.png

877500290b71079f45aa0a1a079b5e97.png

3  总结

事务的机制是通过视图(read-view)来实现的并发版本控制(MVCC),不同的事务隔离级别创建读视图的时间点不同。

可重复读是每个事务重建读视图,整个事务存在期间都用这个视图。

读已提交是每条 SQL 创建读视图,在每个 SQL 语句开始执行的时候创建的。隔离作用域仅限该条 SQL 语句。

读未提交是不创建,直接返回记录上的最新值

串行化隔离级别下直接用加锁的方式来避免并行访问。

这里的视图可以理解为数据副本,每次创建视图时,将当前已持久化的数据创建副本,后续直接从副本读取,从而达到数据隔离效果。

更多有关事务隔离级别实现的方式请参考下一篇文章。

8539ebed4b7467fad299cade82ddda20.gif

●美团二面:给我说说怎么限流?最好能结合自己的项目经验来阐述

●咱们团队早就不用try-catch-finally关闭资源了!

●这月绩效差点没了!搞了一个“新人拼团”活动遇到黑产,搭进去了8台服务器...

●美团二面:给我说说怎么限流?最好能结合自己的项目经验来阐述

7d0875e6c08ca6424bdc50b6677dca85.png

点亮  400558a8741e328fd9ad7112c8c0bf27.png ,告诉大家你也在看
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值