虽然平时已经很少使用MySQL了,但是数据库作为基本技能仍然不能忘,最近在学习数据库隔离级别,在此写下个人理解以备复习。

大家都知道数据库事务ACID(原子性、一致性、隔离性和持久性)的四个特征,也知道数据库存在三种并发问题(脏读、不可重复读、幻读),以及针对性的四种隔离级别(读未提交、读已提交、可重复读、序列化)。

解决与否 脏读 不可重复读 幻读
读未提交 Yes Yes Yes
读已提交 No Yes Yes
可重复读 No No Yes
串行化 No No No

特别提醒一句,隔离级别作用在连接(或会话)级别。客户端每次连接数据库的时候,都要根据自己对一致性的需求程度合理设置自己的事务隔离级别。

那么问题来了,MySQL底层(下文均指InnoDB引擎)是采用何种技术来实现这四种隔离级别的呢?

读未提交

MySQL全表的数据存储在以主键为排序值的B+树索引中,叶子节点存储了相应主键的整行记录。需要指出的是,叶子节点的数据都是最新的数据,可能是事务提交后的一致状态,也可能是事务执行中的中间值(可能被回滚)。

当隔离级别设置为RU时:

  • 所有的读不加锁,读到的都是叶子节点上最新的值,性能最好。
  • 所有的写(更新、插入、删除)加行级排斥锁,不存在脏写的问题,写完就释放锁。

读已提交

当隔离级别是RC和RR时,就要谈到大名鼎鼎的MVCC(多版本控制) 技术。通过在每行加入若干隐藏的字段,它实现了不加锁的读操作,性能较好。

  • 先说RC级别的写操作,MySQL依然加行级排斥锁。事务开始时会往UNDO日志中写入当前的有效记录值,B+树叶子节点的隐藏列DATA_ROLL_PTR会存储指向该UNDO记录的指针。顺着行的DATA_ROLL_PTR的指针形成一个链表,记录该行数据的有效的历史记录。
  • 再说不加锁的读操作,如果叶子节点正被其他事务锁定,那么MySQL顺着叶子节点的DATA_ROLL_PTR指针找到上一个有效的历史记录即可。

可重复读

在事务开始的时候,除了正常往UNDO日志中写回滚的数据外,会创建一个ReadView,记录了当前活跃的其他事务的ID,其中最小值为Tmin,最大值为Tmax。

当执行SELECT操作时,MySQL顺着行记录的DATA_ROLL_PTR指针查找符合条件的历史版本。这里就用到了另一个隐藏列DATA_TRX_ID,其中存储的是更新该记录的事务ID(事务ID是全局递增且唯一的)。如果DELETE_BIT为1,则代表ID为DATA_TRX_ID的事务对当前行执行了删除。

扫描历史版本串成的链表的过滤条件是:

  1. 如果当前记录的DATA_TRX_ID小于Tmin(之前存在的数据),那么由DELETE_BIT决定是否可见;否则,转2。
  2. 如果当前记录的DATA_TRX_ID小于Tmax,且不在活跃的事务ID集合中,那么由DELETE_BIT决定是否可见视为可见;否则,转3。
  3. 否则视为不可见,顺着DATA_ROLL_PTR进入上一个历史版本,或因为到头而结束回溯。

因为插入的数据版本号要么在活跃事务ID集合内、要么小于当前事务ID,所以MVCC机制同时解决了幻读问题。

需要指出的是,以上三个隔离级别中的读均为普通的SELECT。如果用的是SELECT ... LOCK IN SHARE MODE或SELCT ... FOR UPDATE,均属于当前读。即加读锁或写锁,读叶子节点最新值。如果更早的事务改了行值,依然会存在不可重复读的情况;如果前后两次读均为当前读,则不会如此(因为第一次读加锁了)。

在RR级别下,如果WHERE的条件列上有唯一索引,那么MySQL只加行级锁;如果是普通索引,会加间隙锁来防止幻读;如果没有索引,就会首先锁表的所有记录、再释放不符合条件的行的锁,因此会大大降低并发写的能力。

串行化

读写均加表级的读写锁即可,直接读主键索引B+树的叶子节点的最新数据。该级别下,数据一致性很强,但是并发写的能力非常差。

MySQL隔离级别的实现的更多相关文章

  1. mysql隔离级别的测试

    mysql提供四种隔离级别,以下分别对四种隔离级别进行测试,更加直观清晰的了解.具体的隔离级别以及其他相关介绍见https://www.cnblogs.com/eric-fang/p/11052304 ...

  2. mysql隔离级别的设置和检索

    001.设置方式: 001.在/etc/my.cnf配置文件中设置,这个格式一定要记清楚呀! transaction-isolation=READ-COMMITTED 这里要写在“-”号不是“_&qu ...

  3. [转帖]MySQL的又一神器-锁,MySQL面试必备

    MySQL的又一神器-锁,MySQL面试必备 https://segmentfault.com/a/1190000020762791 lock 低一级的是 latch   原文链接:blog.ouya ...

  4. 一文彻底读懂MySQL事务的四大隔离级别

    前言 之前分析一个死锁问题,发现自己对数据库隔离级别理解还不够清楚,所以趁着这几天假期,整理一下MySQL事务的四大隔离级别相关知识,希望对大家有帮助~ 事务 什么是事务? 事务,由一个有限的数据库操 ...

  5. MySQL 面试必备:又一神器“锁”,不会的在面试都挂了

    1 什么是锁 1.1 锁的概述 在生活中锁的例子多的不能再多了,从古老的简单的门锁,到密码锁,再到现在的指纹解锁,人脸识别锁,这都是锁的鲜明的例子,所以,我们理解锁应该是非常简单的. 再到MySQL中 ...

  6. 事务的隔离级别与MVCC

    提到数据库,你多半会联想到事务,进而还可能想起曾经背得滚瓜乱熟的ACID,不知道你有没有想过这个问题,事务有原子性.隔离性.一致性和持久性四大特性,为什么偏偏给隔离性设置了级别? 一切还得从事务说起. ...

  7. MySQL 四种事务隔离级的说明

    很早之前写的文章,重新回顾和学习下: 按照SQL:1992 事务隔离级别,InnoDB默认是可重复读的(REPEATABLE READ).MySQL/InnoDB 提供SQL标准所描述的所有四个事务隔 ...

  8. MySQL事务隔离级别的实现原理

    回顾 在MySQL的众多存储引擎中,只有InnoDB支持事务,所有这里说的事务隔离级别指的是InnoDB下的事务隔离级别. 读未提交:一个事务可以读取到另一个事务未提交的修改.这会带来脏读.幻读.不可 ...

  9. Spring事务管理与数据库隔离级别的关系(Spring+mysql)

    之前写过一篇文章<数据库隔离级别(mysql+Spring)与性能分析 >,里面很多问题写的不是很专业,也不是很有逻辑性,现在重新整理一下,希望对大家有帮助. 这部分通过两天时间反复的 ...

随机推荐

  1. [Linux]经典面试题 - 系统管理 - 备份策略

    [Linux]经典面试题 - 系统管理 - 备份策略 目录 [Linux]经典面试题 - 系统管理 - 备份策略 一.备份目录 1.1 系统目录 1.2 服务目录 二.备份策略 2.1 完整备份 2. ...

  2. HTTP首部字段详解

    HTTP首部字段详解 在HTTP/1.1规范中定义了47种首部字段,总共分为四大类: 通用首部字段 -- 请求报文和响应报文两方都会使用的首部 请求首部字段 -- 从客户端向服务器端发送请求报文时使用 ...

  3. 玩转STM32MP157- 使用fbtft驱动 lcd ili9341

    之前使用了 fbtft 成功驱动了lcd st7735r,现在尝试下驱动 ili9341, 配置 跟之前用 fbtft 驱动 st7735r 一样,先用 make menuconfig 配置内核,添加 ...

  4. C++智能指针之shared_ptr与右值引用(详细)

    1. 介绍 在 C++ 中没有垃圾回收机制,必须自己释放分配的内存,否则就会造成内存泄露.解决这个问题最有效的方法是使用智能指针(smart pointer).智能指针是存储指向动态分配(堆)对象指针 ...

  5. consul 多节点/单节点集群搭建

    三节点配置 下载安装包 mkdir /data/consul mkdir /data/consul/data curl -SLO https://github.com/consul/1.9.5/con ...

  6. Linux之 du的用法

    du 显示目录和文件的大小,常用命令为 du -sh * du -sm * | sort -n //统计当前目录大小 并按大小 排序 du 无参数 显示当前路径下的目录大小和子目录大小 -b/-k/- ...

  7. 使用Hugo框架搭建博客的过程 - 部署

    前言 完成前期的准备工作后,在部署阶段需要配置服务器或对象存储服务. 对象存储和服务器对比 对象存储平台 国内有阿里云OSS.腾讯COS.又拍云.七牛云等.国外有Github Pages.Netlif ...

  8. 关键字abstract和static总结

    1.  abstract:意为抽象,在Java中可以修饰方法或者类 (1)修饰方法,这个方法是抽象方法,无方法体,这个类一定是抽象类,这个类的子类必须实现这个抽象方法: (2)修饰类,这个类一定是抽象 ...

  9. Python - 字符串常用函数详解

    str.index(sub, start=None, end=None) 作用:查看sub是否在字符串中,在的话返回索引,且只返回第一次匹配到的索引:若找不到则报错:可以指定统计的范围,[start, ...

  10. CTF-OldDriver-writeup

    题目信息: 有个年轻人得到了一份密文,身为老司机的你能帮他看看么? 附件:enc.txt [{"c": 73660675747411714617220651332429160804 ...