“隔离级别” 出于MySQL四大特性(ACID)中的“I”,也就是隔离性。目的是实现数据、事务一致性“C”。

MySQL在多线程并发场景下,可能会出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)这类并发问题,为了解决这些问题,引申出“隔离级别”的概念。

谈隔离级别之前,你首先需要知道,隔离得越严实,效率就会越低。隔离就像是生活中那一件件锁事儿,枷锁越多,活得越累。在很多时候,我们都要在二者之间寻找一个平衡点。

小伙伴想精准查找自己想看的MySQL文章?喏 → MySQL专栏目录 | 点击这里

目录

测试数据准备

并发场景下事务存在的数据问题

1. 脏读(针对的是未提交读数据)

2. 不可重复读(针对其他提交前后,读取数据本身的对比)

3. 幻读(针对其他提交前后,读取数据条数的对比)

隔离级别概述

实例分析

读未提交(RU):

读提交(RC):

可重复读(RR)

串行(xíng)化(S)

原理描述

四种隔离级别的问题解决情况

测试建表语句

总结


测试数据准备

测试表是一些好朋友客串一下,请原谅我的不要脸【/偷笑】。(建表语句在文章末尾)

mysql> select * from department;
+----+-----------+-----+-----+------------+------+-----------+
| ID | NAME      | SEX | AGE | CLASS      | PAY  | HOBBY     |
+----+-----------+-----+-----+------------+------+-----------+
|  1 | 陈哈哈    | 男  |  25 | 技术1部    | 3000 | 摸鱼      |
|  2 | 扈亚鹏    | 男  |  25 | 技术1部    | 4000 | 美食      |
|  3 | 刘晓莉    | 女  |  24 | 技术1部    | 4000 | 摸鱼      |
|  5 | 徐立楠    | 女  |  24 | 技术1部    | 4000 | 阅读      |
|  6 | 顾昊      | 男  |  25 | 技术1部    | 4000 | 摸鱼      |
|  7 | 陈子凝    | 女  |  25 | 技术1部    | 5000 | 看电影    |
| 14 | 朱志鹏    | 男  |  25 | 技术1部    | 5000 | 看小说    |
| 19 | 李昂      | 男  |  27 | 技术1部    | 7000 | 看片儿    |
+----+-----------+-----+-----+------------+------+-----------+
8 rows in set (0.00 sec)

为了更好理解下文,这里先给出个业务场景:

老板:原来陈哈哈是我失散多年的大侄子!财务,给 “陈哈哈” 的工资涨 “10000” 大洋。

陈哈哈:谢谢老叔!MUA~

并发场景下事务存在的数据问题

下面我们介绍一下脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)这三类并发问题,以及每种问题出现的原理及场景。

  • 1. 脏读(针对的是未提交读数据)

事务A修改了数据,但未提交,而事务B查询了事务A修改过却没有提交的数据,这就是脏读,因为事务A可能会回滚。

场景:老板(老叔)大喊了一嗓子,但没有指定哪个财务改。财务A大姐和财务B大哥都听到了,但他俩不知道由谁来改,就分别进行了下方流程操作:

时间点 事务A(财务大姐) 事务B(财务大哥) 陈哈哈
T1

(财务大姐要给我改,查到工资:3000)

Begin;

SELECT PAY from department where `NAME` = '陈哈哈';

 
T2 UPDATE department SET ` PAY` = ` PAY` + 10000 where `NAME` = '陈哈哈';

(财务大哥看看财务大姐改没改)

Begin;

 
T3 (财务大姐突然发现财务大哥也在给我改)

(一查发现。哦!已经改了)(工资:13000)

SELECT PAY from department where `NAME` = '陈哈哈';

 
T4  

(财务大哥就继续去摸鱼了)

commit;

 
T5

(就把事务A回滚了)

rollback;

   
T6     ???
T7   ???

就这样,因为 “脏读”就导致我每个月少1万大洋?

  • 2. 不可重复读(针对其他提交前后,读取数据本身的对比)

事务A 先 查询了工资金额,是3000块钱,未提交 。事务B在事务A查询完之后,修改了工资金额,变成了13000, 在事务A前提交了;如果此时事务A再查询一次数据,就会发现钱跟上一次查询不一致,是13000,而不是3000。这就是不可重复读。强调事务A对要操作的数据被别人修改了,但在不知请的情况下拿去做之前的用途。

场景同上:老板嗷一嗓子,但没有指定哪个财务改。财务A大姐和财务B大哥都听到了,但他俩不知道由谁来改,就分别进行了下方流程操作:

时间点 事务A(财务大姐) 事务B(财务大哥)
T1

(财务大姐要给我改,查到工资:3000)

Begin;

SELECT PAY from department where `NAME` = '陈哈哈';

(财务大哥也要给我改,查到工资:3000)

Begin;

SELECT PAY from department where `NAME` = '陈哈哈';

T2 (财务大姐喝了口水)

(财务大哥直接改了)

UPDATE department SET ` PAY` = ` PAY` + 10000 where `NAME` = '陈哈哈';

T3

(大姐正想改,突发强迫症,想再查一下,查到工资:13000)

SELECT PAY from department where `NAME` = '陈哈哈';

T4 (大姐:???)

(财务大哥就继续去摸鱼了)

commit;

T5

(最终大姐回滚了,虽然并没有改什么,但你至少明白了什么是“强迫症”)

rollback;

 
T6 (大姐把BUG报给了产品部)  
T7

(一位35岁程序员被祭天)

 

对于不可重复读,说简单点就是同一个事物内,查到的结果都不一致,就失去了MySQL的“一致性”,这是很严重的错误。你想,如果财务大姐没有二次确认,而是直接以第一次查询为准,又给我加了1万怎么办?想想还有点小激动呢。

  • 3. 幻读(针对其他提交前后,读取数据条数的对比)

幻读是指在同一个事务中,存在前后两次查询同一个范围的数据,但是第二次查询却看到了第一次查询没看到的行,一般情况下只新增。

事务A先修改了某个表的所有纪录的状态字段为已处理,未提交;事务B也在此时新增了一条未处理的记录,并提交了;事务A随后查询记录,却发现有一条记录是未处理的,很是诧异,刚刚不是全部修改为已处理嘛,以为出现了幻觉,这就是幻读。

场景:老板每个月审批一次涨薪(审批表:shenpiTable),这时财务刚刚把我的工资申请提交了,老板正好在审批。一键审批通过后,突然看到了一条新的“未审批”记录(新增的),还是大侄子陈哈哈的。

老板:有幻觉?有BUG!!等等,我如果假装看不到这月是不是就省了1万块大洋?

陈哈哈:???

时间点 事务A(老板) 事务B(财务大哥)
T1

(老板审批加工资申请,并没有注意到“陈哈哈”)

Begin;

SELECT * from shenpiTable where Status = '未通过';

(财务大哥准备给我提交涨工资申请记录)

Begin;

SELECT * from shenpiTable where Status = '未通过';

T2 (老板喝了口水)

(财务大哥摸了摸鱼)

T3

(老板一键通过了,头都没抬那种~)

UPDATE shenpiTable SET  Status = ‘通过’ where shenpiTable = ‘未通过’;

(财务大哥摸了摸鱼)

T4  

(财务大哥新增一条我的申请记录)

insert into shenpiTable values(“xxx”,"陈哈哈",“未通过”);

T5

(老板又确认一下,突然发现我的审批还没通过。一脸懵逼,突然想到了什么,果断commit,笑嘻嘻的去洗脚了。)

SELECT * from shenpiTable where Status = '未通过';

commit;

commit;
T6    
T7

(第二天听到又有一位程序员被我打死)

 
  • 脏读说的是事务知道了自己本不应该知道的东西,强调的动作是查询,我看到了自己不该看的东西 ;
  • 不可重复读强调的是一个人查的时候,其他人却可以增删改, 但我却不知道数据被改了,还拿去做了之前的用途;
  • 幻读强调的是我修改了数据,等我要查的时候,却发现有我没有修改的记录,为什么,因为有其他人插了一条新的。

隔离级别概述

为了解决上述问题,MySQL制定了四种不同的“隔离级别”,包括:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable )。

隔离级别 效果
读未提交(RU) 一个事务还没提交时,它做的变更就能被别的事务看到。(别的事务指同一时间进行的增删改查操作)
读提交(RC) 一个事务提交(commit)之后,它做的变更才会被其他事务看到。
可重复读(RR) 一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
串行(xíng)化(S) 正如物理书上写的,串行是单线路,顾名思义在MySQL中同一时刻只允许单个事务执行,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

实例分析

(场景再现)老板:原来陈哈哈又双叒(ruò)叕(zhuó)是我失散多年的大侄子!财务,把 “陈哈哈” 的工资涨 “10000” !

以下表中的两个事务为例,看看在不同隔离级别下,分别会出现什么结果。能否避免上述问题呢?

时间点(宝强绿) 事务A 事务B
T1

Begin;

SELECT PAY from department where `NAME` = '陈哈哈';

(查询工资:3000)

 
T2   Begin;
T3  

SELECT PAY from department where `NAME` = '陈哈哈';

(查询工资:3000)

T4   UPDATE department SET ` PAY` = `PAY` + 10000 where `NAME` = '陈哈哈';
T5

SELECT PAY from department where `NAME` = '陈哈哈';

(查询工资:Res_A1)

 
T6   commit;
T7

SELECT PAY from department where `NAME` = '陈哈哈';

(查询工资:Res_A2)

 
T8 commit;  
T9

SELECT PAY from department where `NAME` = '陈哈哈';

(查询工资:Res_A3)

 
  • 读未提交(RU):

读未提交 Res_A1 Res_A2 Res_A3
结果 13000 13000 13000

在RU隔离级别下,事务A 在T5时刻,就可以提前读到未提交的事务B 结果。

  • 读提交(RC):

读提交 Res_A1 Res_A2 Res_A3
结果 3000 13000 13000

读提交又叫读已提交,在RC隔离级别下,事务A 需要在 事务B commit提交后,才能看到事务B 修改的结果。所以在T5时刻,事务A 查到的陈哈哈的工资是 3000。

  • 可重复读(RR)

可重复读 Res_A1 Res_A2 Res_A3
结果 3000 3000 13000

可重复读是MySQL默认的隔离级别,在RR级别下,对于所有进行中(begin - commit)的事务,比如事务A,无论执行多少次SELECT(查询表 department ),只能看到的是同一张 department 表的结果视图(ReadView),该视图(ReadView)是在本事务启动(begin)时生成的,在事务A 结束(commit)后释放。该隔离级别会保证单事务内查看视图的一致性,称为“可重复读”。

  • 串行(xíng)化(S)

串行化 Res_A1 Res_A2 Res_A3
结果 3000 3000 13000

串行化隔离级别不支持并发事务,由于事务A 早于事务B,事务A执行SELECT时,就给 department 表加了锁,事务B 需要等事务A 结束后才能执行,因此T5、T7时刻是 3000,T8时刻事务A提交,事务B释放锁并执行,最后T9时刻查到我的工资是 13000。

原理描述

在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。在MySQL默认的隔离级别“可重复读”隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。在“读提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的。这里需要注意的是,“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;而“串行化”隔离级别下直接用加锁的方式来避免并行访问。

我们可以看到在不同的隔离级别下,数据库行为是有所不同的。Oracle 数据库的默认隔离级别其实就是“读提交”,因此对于一些从 Oracle 迁移到 MySQL 的应用,为保证数据库隔离级别的一致,你一定要记得将 MySQL 的隔离级别设置为“读提交”。

配置的方式是,将启动参数 transaction-isolation 的值设置成 READ-COMMITTED。你可以用 show variables 来查看当前的值。

mysql> show variables like 'transaction_isolation';+-----------------------+----------------+
| Variable_name | Value |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+

总结来说,存在即合理,每种隔离级别都有自己的使用场景,你要根据自己的业务情况来定。我想你可能会问那什么时候需要“可重复读”的场景呢?我们来看一个数据校对逻辑的案例。

假设你在管理一个个人银行账户表。一个表存了每个月月底的余额,一个表存了账单明细。这时候你要做数据校对,也就是判断上个月的余额和当前余额的差额,是否与本月的账单明细一致。你一定希望在校对过程中,即使有用户发生了一笔新的交易,也不影响你的校对结果。

这时候使用“可重复读”隔离级别就很方便。事务启动时的视图可以认为是静态的,不受其他事务更新的影响。

四种隔离级别的问题解决情况

标题 脏读 不可重复读 幻读
读未提交(RU) × × ×
读提交(RC) × ×
可重复读(RR)
串行(xíng)化(S)

测试建表语句

-- 建表语句
DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (`ID` int(11) NOT NULL AUTO_INCREMENT,`NAME` varchar(30) CHARACTER SET utf8mb4 NOT NULL,`SEX` char(2) NOT NULL,`AGE` int(11) NOT NULL,`CLASS` varchar(10) NOT NULL,`PAY` int(11) NOT NULL,`HOBBY` varchar(100) DEFAULT NULL,PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;
INSERT INTO `department` (`ID`, `NAME`, `SEX`, `AGE`, `CLASS`, `PAY`, `HOBBY`) VALUES ('1', '陈哈哈', '男', '25', '技术1部', '3000', '摸鱼');
INSERT INTO `department` (`ID`, `NAME`, `SEX`, `AGE`, `CLASS`, `PAY`, `HOBBY`) VALUES ('2', '扈亚鹏', '男', '25', '技术1部', '4000', '美食');
INSERT INTO `department` (`ID`, `NAME`, `SEX`, `AGE`, `CLASS`, `PAY`, `HOBBY`) VALUES ('3', '刘晓莉', '女', '24', '技术1部', '4000', '摸鱼');
INSERT INTO `department` (`ID`, `NAME`, `SEX`, `AGE`, `CLASS`, `PAY`, `HOBBY`) VALUES ('5', '徐立楠', '女', '24', '技术1部', '4000', '阅读');
INSERT INTO `department` (`ID`, `NAME`, `SEX`, `AGE`, `CLASS`, `PAY`, `HOBBY`) VALUES ('6', '顾昊', '男', '25', '技术1部', '4000', '摸鱼');
INSERT INTO `department` (`ID`, `NAME`, `SEX`, `AGE`, `CLASS`, `PAY`, `HOBBY`) VALUES ('7', '陈子凝', '女', '25', '技术1部', '5000', '看电影');
INSERT INTO `department` (`ID`, `NAME`, `SEX`, `AGE`, `CLASS`, `PAY`, `HOBBY`) VALUES ('14', '朱志鹏', '男', '25', '技术1部', '5000', '看小说');
INSERT INTO `department` (`ID`, `NAME`, `SEX`, `AGE`, `CLASS`, `PAY`, `HOBBY`) VALUES ('19', '李昂', '男', '27', '技术1部', '7000', '看片儿');

总结

以上就是对MySQL中三种并发数据问题以及四种隔离级别的介绍,有些朋友会问,那这几种隔离级别解决上述三种问题的原理是什么呢?可重复读RR是如何解决幻读问题的?

请关注后续文章《MySQL的MVCC原理及如何解决数据问题》、《灵魂拷问:InnoDB是如何解决幻读的》

一张照片背后的故事

一对在沈阳打工的抚顺老夫妇
没有锦衣玉食的生活
却有相互陪伴和相濡以沫的日子
而这种平凡的不能再平凡的生活
63岁的老何却无法再继续享受到了
在16年4月17日
他老伴从药房买药后
走出来就倒地猝死了
老何到场后在-24°的冰天雪地里抱着妻子的尸体
坐了两个小时不愿撒手
当别人过来安慰的时候
老何只是说:“我不冷,我就想最后再抱她一会儿,以后都没有机会了”

上个厕所的功夫,搞懂MySQL事务隔离级别相关推荐

  1. mysql 默认事务隔离级别_上个厕所的功夫,搞懂MySQL事务隔离级别

    "隔离级别" 出于MySQL四大特性(ACID)中的"I",也就是隔离性.目的是实现数据.事务一致性"C". MySQL在多线程并发场景下, ...

  2. 上个厕所的功夫,搞懂MySQL事务隔离级别,Java学习视频百度云盘

    | 14 | 朱志鹏 | 男 | 25 | 技术1部 | 5000 | 看小说 | | 19 | 李昂 | 男 | 27 | 技术1部 | 7000 | 看片儿 | ±-±----------±--- ...

  3. 从实际蹲坑中涨姿势之——彻底搞懂Mysql事务隔离级别

    一.业务背景 最近在做一个类似于任务分发的平台,分为任务管理平台和作业机,任务管理平台负责接收作业机的请求,并为作业机分配任务,所有的任务都存在表t_task_info,其使用一个字段task_sta ...

  4. 3分钟搞懂MySQL事务隔离级别及SET TRANSACTION影响事务

    导读:MySQL支持SQL:1992标准中的所有事务隔离级别,使用SET TRANSACTION来设置不同的事务隔离级别或访问模式,我们一起实战下它的效果. 我们都知道,MySQL的内置引擎中只有In ...

  5. 五分钟搞清楚MySQL事务隔离级别

    好久没碰数据库了,只是想起自己当时在搞数据库的时候在事务隔离级别这块老是卡,似懂非懂的.现在想把这块整理出来,尽量用最简洁的语言描述出来,供新人参考. 首先创建一个表account.创建表的过程略过( ...

  6. 揭秘Mysql事务隔离级别之可重复读

    揭秘Mysql事务隔离级别之可重复读 1.可重复读的来源 2.何为不可重复读 3.那么可重复读和不可重复读究竟有什么关系呢? 4.模拟不同事务隔离级别对不可重复的处理情况(有线程执行顺序). 4.1. ...

  7. Mysql事务隔离级别及MVCC(多版本并发控制)

    一.MySQL事务隔离级别 先注明一点:以下讨论都是在多事务并发的情境下讨论的 事务的特性(InnoDB引擎才有事务): ACID 原子性:一个事务不可再分割,要么都执行要么都不执行 一致性:一个事务 ...

  8. mysql 事务隔离级别实现原理_MySQL事务隔离级别和实现原理 - 米扑博客

    开发中经常提到数据库的事务,那你知道数据库还有事务隔离的说法吗, 事务隔离还有隔离级别,那什么是事务隔离,隔离级别又是什么呢? MySQL 事务 本文所说的 MySQL 事务都是指在 InnoDB 引 ...

  9. 5、MySQL事务隔离级别详解

    事务的隔离性就是指当多个事务同时运行时,各事务之间相互隔离,不可互相干扰.如果事务没有隔离性,就容易出现脏读.不可重复读和幻读等情况. 为了保证并发时操作数据的正确性,数据库都会有事务隔离级别的概念. ...

最新文章

  1. MySql清空表的方法介绍 : truncate table 表名
  2. java多态的应用场景_Java培训SE基础之多态的应用场景
  3. 基于macos的Homebrew常用命令和使用教程(你得看❤️)
  4. python递归求13的n次方_Python题目:递归的简单题目,求阶乘,求n-m的累积和,求斐波那契...
  5. python numpy 技巧
  6. 千万数据去重_如何在 1 秒内做到大数据精准去重?
  7. 旁枝末梢(我好像稍微理解了mvc和mvvm)
  8. DS实验题 最大最小
  9. 关于Web2.0概念解释
  10. Sigar介绍和配置
  11. ClientKey实现登录QQ空间,并设置背景音乐
  12. android java char_Android句子迷客户端
  13. 软件工程经济学课程报告
  14. 人工智能(AI)在未来的发展趋势和应用场景
  15. CIDR(构成超网)
  16. COLA 4.x和DDD项目实践精粹
  17. TCP状态转换图——简述11个状态
  18. 沧州一中高考2021成绩查询,沧州一中2019高考喜报成绩、一本二本上线人数情况...
  19. C语言求任意范围内的素数
  20. ffmpeg 命令行 pcm 编码 MP3

热门文章

  1. 记录-沪东船厂两台600T门吊倒塌事故
  2. 记录:调用山东天地图的时候跨域解决方案
  3. 网页报告不能直接转换成Word、PDF格式怎么办?Spire.doc控件可以轻松解决
  4. 数据分析思维之用户标签
  5. 基于三相坐标系状态方程的感应电动机起动动态计算matlab程序
  6. 九宫格游戏-第14届蓝桥杯省赛Scratch初级组真题第5题
  7. 液晶电视工作原理(转)
  8. 10 个杀手级的 Python 自动化脚本
  9. 啥?不用PhotoShop也能做图片?详细教程走起!
  10. gperftools的安装与使用