虽然平时已经很少使用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. Java程序安装失败

      检查文件路径,应该不含中文汉字,空格以及特殊字符.应将jdk的安装目录设置为纯英文路径. 是否有多个安装程序同时运行,若多点安装程序则会安装失败,打开任务管理器,查看是否有多个安装程序运行 注册表 ...

  2. Pandas高级教程之:处理缺失数据

    目录 简介 NaN的例子 整数类型的缺失值 Datetimes 类型的缺失值 None 和 np.nan 的转换 缺失值的计算 使用fillna填充NaN数据 使用dropna删除包含NA的数据 插值 ...

  3. vs2008中安装dev之后输入代码会输入代码段但是报错,可能解决方法

    vs2008工具栏DevExpress→Options 取消勾选这个

  4. Spring学习日记01_IOC_xml的三种注入方式

    什么是IOC 控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理 使用IOC目的:为了耦合度降低 做入门案例就是IOC实现 IOC底层原理 xml解析 工厂模式 反射 原始方式 cla ...

  5. 学会使用Python的threading模块、掌握并发编程基础

    threading模块 Python中提供了threading模块来实现线程并发编程,官方文档如下: 官方文档 添加子线程 实例化Thread类 使用该方式新增子线程任务是比较常见的,也是推荐使用的. ...

  6. 安聊服务端Netty的应用

    Netty简介 Netty是一个面向网络编程的Java基础框架,它基于异步的事件驱动,并且内置多种网络协议的支持,可以快速地开发可维护的高性能的面向协议的服务器和客户端. 安聊简介 安聊是一个即时聊天 ...

  7. ELK Stack企业日志平台文档

                                          ELK Stack企业日志平台文档           实验环境 主机名 IP地址 配置 系统版本 用途 controlno ...

  8. 15、linux文件、目录的权限及如何改变权限(root用户不受任何权限的限制)

    15.1.linux普通文件的读.写.执行权限说明: r:读,表示具有读取\阅读文件内容的权限: w:可写,表示具有新增,修改文件内容的权限: 如果没有r配合,那么vi编辑文件会提示无法编辑(但可以强 ...

  9. mysql某建表语句

    CREATE TABLE `product_info`( `product_id` VARCHAR(32) NOT NULL COMMENT '主键', `product_name` VARCHAR( ...

  10. XSS challenges 1-10

    学长发的xss靶场,刚好js学完了,上手整活. 这个提示说非常简单,直接插入就完事了 <script>alert(document.domain)</script> 第二关. ...