摘要:

对于关系型数据库MySQL,想必各位小伙伴并不陌生,恰逢金九银十、跳槽涨薪之际,Debug特意给诸位小伙伴整理了一些关于MySQL方面的知识点,一来是加深巩固MySQL技术栈,二来可以在跳槽时的面试提供一些助攻;这些知识点将分2-3篇系列文章进行发布,感兴趣的小伙伴可以持续关注哦~

本文我们将从MySQL的几种事务隔离级别开始撸起,从MySQL事务的概念讲起,再到事务的4个基本特性、事务并发时产生的问题,最后再到MySQL的4种事务隔离级别的介绍以及对应的实战。

内容:

  • 事务简介与4个基本特性

事务(Transaction)一词是计算机术语,一般指的是要做的或者所做的事情,在计算机编程领域指的是访问并更新数据库中各个数据项的一个执行单元,一般是由两段核心命令之间执行的全体操作组成,即事务开始“begin transaction”、事务结束“end transaction”;而在这两段操作命令之间,常见的就有:提交事务commit 、回滚事务rollback 等等;

而事务有4个基本特性,即我们常说的“酸性”:ACID,每个字母代表一个特性,具体包括:

(1)原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节;事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生过一样;也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位;

(2)一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏;比如A向B转账,不可能A扣了钱,B却没收到;

(3)隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰;比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账;

(4)持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚;

二、事务并发时产生的问题

从上述中我们已经知晓了“事务”其实就是一个或者一组操作单元,如“新增用户信息”、

“更新用户信息同时更新用户头像”等等均为实际项目开发中常见的事务,这一事务涉及到的相关操作要么全部都做完、要么全部都不做;

然而在某些特殊的场景下,比如多线程并发操作同个数据库表 或者 同份数据,则有可能会出现事务的并发问题,这些问题可以归结为3类,即:

(1)脏读:事务A读取了事务B更新的数据,然后B执行回滚操作,此时A读取到的数据即是脏数据;

(2)不可重复读:事务 A 多次读取同一份数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一份数据时,得到的结果不一致;

(3)幻读:管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A修改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

附注:不可重复读的 和 幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,而解决幻读需要锁表

  • 4种事务隔离级别

既然数据库在使用过程中有可能会出现事务并发的各种问题,那么自然而然我们需要去寻找相应的解决方案;幸运的是,目前各大主流的数据库如MySQL、Oracle、Sql Server等等本身就自带了相应的解决方案,即传说中的“事务隔离级别”;

下面我们以MySQL为例,介绍它的4种事务隔离级别,每一种均用于解决上述事务并发时产生的各种问题,如下表格所示:

事务隔离级别

脏读

不可重复读

幻读

读未提交
(read-uncommitted)

可能出现

可能出现

可能出现

读已提交
(read-committed)

不可能出现

可能出现

可能出现

可重复读
(repeatable-read)

不可能出现

不可能出现

可能出现

串行化

(serializable)

不可能出现

不可能出现

不可能出现

(1)读未提交(read-uncommitted):顾名思义,指的是并发的事务A、B在操作同一份数据时由于先后顺序、事务没提交以及回滚等原因导致最终数据不一致性的现象;

比如变量a初始值为1,即a=1,事务A先读取到变量a,此时Aa=1,在A准备进入后续相关操作之前,B事务对a变量执行了减1操作,但是还没有提交该事务,此时在B看来a仍然为1,即Ba=1(因为还没有提交“减1”操作对应的事务);

而出乎意料的是,此时A事务再次查询变量a的值时会发现a已经变为0了,即Aa=0(这就是所谓的“读已提交”,而理论上应该是1才对,因为B还没提交“减1”操作对应的事务),然后A带着变量a=0进行了后续的操作……