之前发过一篇文章,简单了解 MySQL 中相关的锁,里面提到了,如果我们使用的 MySQL 存储引擎为 InnoDB ,并且其事务隔离级别是 RR 可重复读的话,是可以避免幻读的。

但是没想到,都 1202 年了都还有人杠,说 InnoDB 的 RR 隔离级别下会出现幻读,只能依靠 gap 和 next-key 这两个锁来防止幻读 ,最开始我还以为是他真的不知道这个点,就跟他聊,最后聊下来发现,发现是在钻牛角尖。

这个在下面讲到 可重复读 的隔离级别时会讲。

本来我觉得事务隔离级别这玩意儿太简单没啥可讲的,但是经过了上面这件事,我打算详细的把事务隔离给讲讲。接下来顺便就把 InnoDB 所有的事务隔离级别给搂一遍。

ACID

在聊事务隔离级别之前,我们需要知道 ACID 模型。


ACID 模型

分别代表:

  • Atomicity 原子性
  • Consistency 一致性
  • Isolation 隔离型
  • Durability 持久性

原子性,代表 InnoDB 事务中,所有的操作要么全部成功,要么全部失败,不会处于某个中间状态。说的更通俗一点,如果事务 A 失败,其所做的所有的更改应该全部回滚。

一致性,主要是保护数据的一致性,防止由于数据库的崩溃而导致的数据一致性问题。举个例子,我们更新 MySQL 的数据,更新的数据会先到 InnoDB 的 Buffer Pool 中,如果此时 MySQL 所在的机器突然意外重启了,如果 InnoDB 没有崩溃恢复机制,之前更新的数据就会丢失,数据的一致性问题就出现了。

很多其他的博客写的是事务开要始前后,数据的完整性没有被破坏。我表示看了根本看不懂,太抽象了。

隔离性,主要是指事务之间的隔离,再具体一点,就是我们本篇文章要讨论的事务隔离级别了。

持久性,主要是指我们新增或者删除了某些数据,一旦成功,这些操作应该需要被持久化到磁盘上去。

ACID 模型可以理解成数据库的设计范式,主要关注点在数据数据、及其本身的可靠性。而 MySQL 中的 InnoDB 就完全遵守 ACID 模型,并且在存储引擎层就支持数据一致性的校验和崩溃恢复的机制。

而 ACID 中的隔离型,就是我们这篇文章中讨论的重点。

事务隔离级别

有很多文章上来就直接介绍事务隔离级别的种类,这个种类啥意思,那个种类怎么用。但我认为应该先了解为什么需要事务隔离级别,以及事务隔离级别到底解决了什么问题,这才是关键。

我们知道 InnoDB 中同时会有多个事务对数据进行操作,举一些例子:

  • 假如事务A需要查询 id=1 的数据,但是事务A查询完毕之后,事务B对 id=1 的数据做了更新,那此时事务A再次执行查询,应该看到更新前的数据还是更新后的数据?
  • 或者还是上面那个例子,事务A读取了事务B的数据,但是如果事务B进行回滚了怎么办?事务A的数据不就变成了脏数据?
  • 又或者事务A读取了 1-3点 的日程安排,有4条,但是事务A读取完成后事务B又向 1-3 点这个时间段插入了一条新的安排,那么事务A如果再次读取,应该显示4条日程安排还是5条?

以上的这些问题,就需要事务隔离级别来回答了。其实以上的三种情况分别对应不可重复读脏读幻读。InnoDB 通过事务隔离级别分别的解决了上面的问题。所有的事务隔离级别如下:

  • READ UNCOMMITTED 读未提交
  • READ COMMITTED 读已提交
  • REPEATABLE READ 可重复读
  • SERIALIZABLE 串行化

InnoDB 默认的事务隔离级别为 REPEATABLE READ

读未提交

事务A读取了事务B还未提交的数据

如果事务B此时出错了进行了回滚,那么事务A读取到的数据就成为了脏数据,从而造成脏读

如果事务B又更新事务A读取的数据,那么事务A再次读取,读取到了事务B修改的结果,这造成了不可重复读

而如果事务B又新增了数据,事务A再次读取,会读取到事务B新增的数据,这造成了幻读

所以总结来说,在读未提交这个隔离级别下,会造成以下的问题:

  • 脏读
  • 不可重复读
  • 幻读

读已提交

事务A读取了事务B已经提交的数据

如果事务B更新了事务A读取到的数据,并且提交,那么当事务A再次进行读取,就会读取到其他事务的变更,就造成了不可重复读

同理,如果事务B新增了数据并且提交,事务A再次进行读取时拿到了事务B刚刚提交的数据,这就造成了幻读。

所以总结来说,在读已提交的隔离级别下,会造成:

  • 不可重复读
  • 幻读

可重复读

事务A不会读取到事务B更新的数据,也不会读到事务B新增的数据

在可重复读场景下,不会出现脏读、不会出现不可重复读,可能会出现幻读

无论事务B做了什么操作,事务A查询到的 id=1 的数据都是张三。

但是,在某些情况下,还是可能会出现 幻读可重复读 只是在某些情况下会产生幻读,但绝对不是 InnoDB 无法避免幻读。首先,InnoDB 在 RR 隔离级别下有很明确的解决幻读的方式,那就是——临键锁,一种组合了 gap 锁和记录锁的锁。

接下来举个例子来看在 RR 隔离级别下,什么情况会出现幻读,什么情况下不会出现幻读。首先是 可能会出现幻读

SELECT * FROM `student` WHERE `id` > 1

由于 InnoDB 有 MVCC 来进行多事务的并发,此时 SELECT 走的是快照读,不会加锁,那么临键锁就无法发挥其作用,如果有其他事务插入了一条数据,那么事务再次执行上面的语句是有可能会查出 id > 1 的数据。

但是如果显示的进行加锁,则可以避免这个问题。

SELECT * FROM `student` WHERE `id` > 1 FOR UPDATE

至于为什么临键锁可以避免幻读,之前的文章已经聊的很清楚,就不在此赘述了。

串行化

所以事务被强制的串行执行

这样从根本上就避免了并发的问题,但是这样会使得 MySQL 的性能下降。因为现在同一时间只能有一个事务在运行。

EOF

关于事务隔离级别就先介绍到这,之后有时间了就把 事务隔离级别 的底层原理给搂一遍。

本篇文章已放到我的 Github github.com/sh-blog 中,欢迎 Star。微信搜索关注【SH的全栈笔记】,回复【队列】获取MQ学习资料,包含基础概念解析和RocketMQ详细的源码解析,持续更新中。

如果你觉得这篇文章对你有帮助,还麻烦点个赞关个注分个享留个言

啥是 MySQL 事务隔离级别?的更多相关文章

  1. [51CTO]新说MySQL事务隔离级别!

    新说MySQL事务隔离级别! 事务隔离级别这个问题,无论是校招还是社招,面试官都爱问!然而目前网上很多文章,说句实在话啊,我看了后我都怀疑作者弄懂没!本文所讲大部分内容,皆有官网作为佐证,因此对本文内 ...

  2. 查询mysql事务隔离级别

    查询mysql事务隔离级别 查询mysql事务隔离级别 分类: DB2011-11-26 13:12 2517人阅读 评论(0) 收藏 举报 mysqlsessionjava   1.查看当前会话隔离 ...

  3. MySQL事务隔离级别测试实例

    https://www.cnblogs.com/huanongying/p/7021555.html MySQL事务隔离级别 事务隔离级别 脏读 不可重复读 幻读 读未提交(read-uncommit ...

  4. Mysql事务-隔离级别

    MYSQL事务-隔离级别 事务是什么? 事务简言之就是一组SQL执行要么全部成功,要么全部失败.MYSQL的事务在存储引擎层实现. 事务都有ACID特性: 原子性(Atomicity):一个事务必须被 ...

  5. MySQL事务隔离级别 解决并发问题

    MySQL事务隔离级别 1. 脏读: 骗钱的手段, 两个窗口或线程分别调用数据库转账表,转账后未提交,对方查看到账后,rollback,实际钱没转. 演示方法: mysql默认的事务隔离级别为repe ...

  6. mysql事务隔离级别、脏读、幻读

    Mysql事务隔离级别本身很重要,再加上可能是因为各大公司面试必问的缘故,在博客中出现的概率非常高,但不幸的是,中国的技术博客要么是转载,要么是照抄,质量参差不齐,好多结论都是错的,对于心怀好奇之心想 ...

  7. mysql事务隔离级别与设置

    mysql数据库,当且仅当引擎是InnoDB,才支持事务: 1.隔离级别 事务的隔离级别分为:未提交读(read uncommitted).已提交读(read committed).可重复读(repe ...

  8. MySQL事务隔离级别(二)

    搞清楚MySQL事务隔离级别 首先创建一个表 account.创建表的过程略过(由于 InnoDB 存储引擎支持事务,所以将表的存储引擎设置为 InnoDB).表的结构如下: 为了说明问题,我们打开两 ...

  9. MySQL事务隔离级别(一)

    本文实验的测试环境:Windows 10+cmd+MySQL5.6.36+InnoDB 一.事务的基本要素(ACID) 1.原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做 ...

  10. 面试突击61:说一下MySQL事务隔离级别?

    MySQL 事务隔离级别是为了解决并发事务互相干扰的问题的,MySQL 事务隔离级别总共有以下 4 种: READ UNCOMMITTED:读未提交. READ COMMITTED:读已提交. REP ...

随机推荐

  1. springboot——简单通过Map将错误提示输出到页面显示

    主要思路:在controller层我们将错误信息put进map中,然后通过视图解析器跳转到目标页面,在目标页面中在通过指定标签内的th:text将错误消息取出. 例: 1.编写controller代码 ...

  2. 给小米路由R1D增加WebDAV服务

    我的R1D是14年买的,原装的硬盘已经不能用了,换了一块从笔记本上退役下来的500G硬盘后继续愉快的使用了-- 当初买这款路由器的原因之一是看中了它的内置硬盘,可以用来备份手机相册.存储智能摄像机录像 ...

  3. Spring Bean 的生命周期总结

    除了使用阶段外,Spring 将 bean 的生命周期定义为实例化.属性填充.初始化和销毁四个阶段,并为每个阶段提供了多个拓展点用于自定义 bean 的创建过程.这篇文章介绍了 bean 的生命周期和 ...

  4. 【Android编程】Java利用apktool编写Metasploit恶意后门注入工具

    /声明:本文作者Kali_MG1937 csdn博客id:ALDYS4 QQ:3496925334 未经许可禁止转载!/ 注意,本文为作者从CSDN搬迁至此的文章 注意!此文章虽然 未被 作者标记到 ...

  5. 【NX二次开发】Block UI 集列表

    属性说明 属性   类型   描述   常规           BlockID    String    控件ID    Enable    Logical    是否可操作    Group    ...

  6. Linux命令(磁盘的卸载与挂载)

    一.光盘挂载与卸载: 1.将光盘CD-ROM(hdc)安装到文件系统的/mnt/cdrom目录下的命令是 C . A mount /mnt/cdrom  B mount /mnt/cdrom /dev ...

  7. 测试MySQL锁的问题

    测试MySQL锁的问题 目录 测试MySQL锁的问题 1 Record Lock 2 Next-Key Lock 2 死锁测试 InnoDB支持三种行锁: Record Lock:单个行记录上面的锁 ...

  8. SpringCloud-OAuth2(三):进阶篇

    上篇文章讲了SpringCloud OAuth 的实战篇,但是在微服务环境下,常常会有一个认证中心. 而普通服务接收到请求后,判断token是否有效并不是自己处理的,因为token的管理统一交给认证中 ...

  9. es6 快速入门 系列 —— promise

    其他章节请看: es6 快速入门 系列 Promise Promise 是一种异步编程的选择 初步认识Promise 用 Promise 来实现这样一个功能:发送一个 ajax,返回后输出 json ...

  10. 精通LED驱动芯片HT1632C指令与编程应用

    HT1632C是一款很常用的LED(数码管或点阵)驱动芯片,虽然官方已经宣布该芯片明年(2021年)即将寿终正寝(停产),但是相同厂家生产的同系列芯片的控制方式通常是相同的(事实上,大多数LED驱动芯 ...