MySQL事务和隔离级别

2019-11-09  本文已影响0人  小马蛋
本文以MySQL数据库为蓝本进行讲解~

事务是什么

事务'封装'了一系列操作,使得这一系列操作变成了一个最小的工作单元,也可以理解为打包、压缩一起带走~,一起退回~

我理解的事务是:对现实世界中的正常约束行为,映射成数据库操作的行为。

例:熊妈吩咐小熊找熊爸要100块钱,熊爸给了小熊,但是熊爸给钱后,不放心,怕小熊出去浪,所以它就一直在监视小熊,看小熊到底给没给熊妈,没给,就要把钱要回来,顺带手揍一顿小熊,如果给了,熊爸心里的石头落地了,放心了,也许会抚摸着小熊的头说:熊孩子长大了。

从熊爸给钱后,开启担忧模式,直到熊妈收到钱,担忧模式关闭,这段时间就是熊爸的事务期!

事务四个特性:

1)原子性 Atomicity

熊爸不可能认可:钱交给小熊了,但是熊妈却没收到钱。熊爸只认可要么钱到熊妈手,或者及时的把钱从小熊那里拿回来。

正常解释:事务内的操作要么全成功,要么全部不成功,里面的步骤不能部分成功部分失败,我们将这样的操作映射,称之为原子性。

2)一致性 Consistency

熊爸给了小熊100,小熊反手一个素质三连,给了熊妈一张欠条,熊妈炸了,熊爸被打了,小熊说医院wifi信号真好~

或者说,小熊给了熊妈50,小熊说医院wifi信号真好~

熊妈要的是钱而不是小熊用卫生纸手绘的欠条!

我们当前的社会是和平的,是盛世,盛世之下有许多条条框框的约定,比如身份证号不能重复;高考100分,应该是上不了清华北大的;工资不能是负的,等等。

数据库的数据最终态应该也是符合现实世界约束的。如果符合这些约束条件我们就可以说这些数据是一致的,符合一致性。当然数据进行操作时我们可以check。

数据库的原子性和隔离性都是为了保证一致性的手段,在操作执行完成后保证符合所有既定的约束则是一种结果。

3)隔离性 Isolation

现实世界中的两次状态转换应该是互不影响的,比如说熊爸向熊妈同时进行的两次金额为5元的转账(假设可以在两个ATM机上同时操作)。那么最后熊爸的账户里肯定会少10元,熊妈的账户里肯定多了10元。但是对应到数据库世界中,事情又变的复杂了一些。为了简化问题,我们粗略的假设熊爸向熊妈转账5元的过程是由下边几个步骤组成的:

步骤一:读取熊爸账户的余额到变量A中,这一步骤简写为read(A)。

步骤二:将熊爸账户的余额减去转账金额,这一步骤简写为A = A - 5。

步骤三:将熊爸账户修改过的余额写到磁盘里,这一步骤简写为write(A)。

步骤四:读取熊妈账户的余额到变量B,这一步骤简写为read(B)。

步骤五:将熊妈账户的余额加上转账金额,这一步骤简写为B = B + 5。

步骤六:将熊妈账户修改过的余额写到磁盘里,这一步骤简写为write(B)。

我们将熊爸向熊妈同时进行的两次转账操作分别称为T1和T2,在现实世界中T1和T2是应该没有关系的,可以先执行完T1,再执行T2,或者先执行完T2,再执行T1,对应的数据库操作就像这样:

转账1.png 侵删

但是很不幸,真实的数据库中T1和T2的操作可能交替执行,比如这样:

转账2.jpg 侵删

如果按照上图中的执行顺序来进行两次转账的话,最终熊爸的账户里还剩6元钱,相当于只扣了5元钱,但是熊妈的账户里却成了12元钱,相当于多了10元钱!

所以对于现实世界中状态转换对应的某些数据库操作来说,不仅要保证这些操作以原子性的方式执行完成,而且要保证其它的状态转换不会影响到本次状态转换,在事务正确提交之前,不允许把事务对该数据的改变提供给任何其他事务,这个规则被称之为隔离性。

4)持久性 Durability

事务内的操作,一旦成功就是永久性的,不会随着时间或者数据库的崩溃而消失,比较好理解,不拿小熊举例了。

上述四个特性简称为ACID

事务的状态

二、事务的隔离级别

为什么会有事务的隔离级别?
我们可以想像一下数据库处于服务器上,每个客户端(系统连接)与数据库的连接,我们可以称之为一个会话(Session),每个客户端都可以在自己的会话内向服务器发出请求,对于数据库来说,数据库可能要同时处理多个请求。

事务有个特性就是隔离性,理论上应该是事务要进行排队,一个一个处理,彼此互不干扰,但是如果这样做就会带来性能问题,一个一个处理的时间响应肯定是不尽如人意的,我们既想保持事务的隔离性,又想让处理性能提升起来。

主流的做法就是在二者之间找平衡点。

先看一看,在并发访问同一数据且不保证串行的情况下会发生哪些情况:

1)脏写

一个事务1修改了另一个未提交事务2的数据,这就发生了脏写,伴随着未提交事务发生异常而导致的回滚,1事务操作的数据也被回滚。
我个人认为,脏写的问题无法容忍!

脏写.jpg
2)脏读

一个事务1读到了另一个未提交事务2的数据,这就发生了脏读。

脏读.png
3)不可重复读

一个事务只能读到其它已提交事务修改过的数据,并且其它事务每对该数据进行修改且提交后,该事务都能查询到最新值,这就是不可重复读。

大家注意"修改"二字!这是区别幻读的重要条件

不可重复读.png
4)幻读

在一个事务内,根据限定条件查询出一些数据,之后另外一个事务又插入了一条符合该限定条件的数据,等到原先事务再查询时,也能把刚刚插入的数据读取出来,这就是幻读。
删除操作也是幻读!

幻读.png

我们上边介绍了事务在并行时可能遇到的几种情况。

按严重程度排序 脏写 > 脏读 > 不可重复读 > 幻读

SQL标准的制定者根据上述情况制定了4中隔离级别:

1)READ UNCOMMITTED 读未提交
2)READ COMMITTED 读已提交
3)REPEATABLE READ 可重复读
4)SERIALIZABLE 串行化

4种隔离级别对应的并发情况可能发生的问题:

隔离级别对应的并发问题.jpg

大家可能注意到,为什么没有脏写呢?无它,脏写的问题太严重了,所以连隔离级别最低的 READ UNCOMMITTED 都不会允许脏写的情况发生。
MySQL的可重复读隔离级别杜绝了幻读的出现!

三、事务分配id的时机

1)读写事务执行过程中,第一次执行增删改操作,InnoDB(或其它支持事务的存储引擎)存储引擎,会为当前事务分配一个事务id,事务id是递增的。

2)对于只读事务,只有在其第一次对某个用户创建的临时表进行增删改时才会为其分配一个事务id(执行查询时用到的内部临时表并不在此范围,和手动CREATE TEMPORARY TABLE创建的用户临时表不一样)

四、结束

数据库事务和隔离级别到此为止,下一篇有可能是应用层事务使用的课题。

学习网络众多文章及掘金小册《MySQL 是怎样运行的:从根儿上理解 MySQL》自己思考、总结、归纳、整理出来的

上一篇下一篇

猜你喜欢

热点阅读