广告
返回顶部
首页 > 资讯 > 数据库 >MySQL事务ACID原理深度解析
  • 415
分享到

MySQL事务ACID原理深度解析

MySQL事务ACID原理深度解析 2018-05-21 01:05:03 415人浏览 无得
摘要

什么是MySQL事务? 事务是指对数据库的一组操作的集合,集合中的sql语句要么全部执行成功,要么就全部失败,如果集合中任一操作出错,则此集合所有对数据库的操作全部回滚。 以常见的购物操作举例,用户下单后要执行订单创建、减库存等一系列操

MySQL事务ACID原理深度解析

什么是MySQL事务?


事务是指对数据库的一组操作的集合,集合中的sql语句要么全部执行成功,要么就全部失败,如果集合中任一操作出错,则此集合所有对数据库的操作全部回滚。

以常见的购物操作举例,用户下单后要执行订单创建、减库存等一系列操作,这些操作就是一个事务,以原子的方式执行,要么全部成功,要么失败回滚,避免出现用户下单了但是库存没有扣减的问题,当然真实环境中的业务要比这个复杂的多,在微服务项目中还会涉及到分布式事务问题。

事务的特性


首先来了解下什么是事务的特性,SQL标准中定义了事务应具有 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)四个特性,简称 ACID

原子性:

指一个事务是一个不可分割的操作集合,其中的操作要么都做,要么都不做;如果其中任意一个SQL执行失败,则整个事务必须回滚,将数据库状态恢复至事务开始之前。

一致性:

指事务执行完成后,数据库完整性约束没有被破坏,事务执行前后都是合法的数据状态。

隔离性:

指不同事务间的操作互相不可见,互不影响,数据库隔离级别主要涉及的就是事务间的隔离性问题。

持久性:

指事务提交后对数据库的修改时永久的,接下来的其他操作或故障不应该对其有任何影响。

 

一、原子性


Mysql日志有很多种,例如Binlog、错误日志、慢查询日志、查询日志等;mysql还提供了事务日志:redo log(重做日志)和undo log(回滚日志)。undo log就是实现事务原子性的关键。

事务执行时对数据库所做的修改,都会写入undo log,例如INSERT、UPDATE、DELETE;如果事务执行失败回滚,则会利用undo log中的信息回滚,执行相反操作:对于每个insert,回滚时会执行delete;对于每个delete,回滚时会执行insert;对于每个update,回滚时会执行一个相反的update把数据改回去。

例如UPDATE操作:当事务执行UPDATE时,undo log 会记录被修改行的主键,修改的列以及修改前后的信息,在事务回滚时使用这些信息回滚。

 

二、持久性


类似于undo log,redo log也属于事务日志。

首先介绍下redo log存在的背景。

InnoDB引擎的数据是存在磁盘中的,我们都知道磁盘IO的数据是很慢的,如果每次读写数据都去做IO,效率会很低。因此,InnoDB采用了缓存机制(Buffer Pool),Buffer Pool中有磁盘数据页的映射。从数据库中读数据前会先从Buffer Pool中读取,如果没有,则从磁盘中读取后放入Buffer Pool中;数据写入时,也是会先写入Buffer Pool中,再由MySQL定期刷入磁盘中,称为“刷脏”。

任何新技术的引用总是会带来新的问题,Buffer Pool机制的使用虽然大幅提升了MySQL的读写效率,但是一旦遇到MySQL宕机,但是Buffer Pool中的数据还没刷入磁盘中,就会导致数据丢失,则破坏了事务的持久性。

综上所述,redo log就是为了解决这个问题,数据修改前,会先将修改记录写入Buffer Pool中,事务提交后,MySQL会将redo log的记录刷入磁盘中。这样即使MySQL宕机,也能保证数据不丢失,启动后根据redo log中的记录恢复数据即可。

 

 三、隔离性


隔离性是事务中最关键的一个特性,我们常说的事务的隔离级别就是面向事务的隔离性来讨论的。InnoDB在不同的隔离级别下使用了不同的实现机制,这一节也是本文的重点内容。

首先我们来了解下事务的隔离级别

SQL标准定义了四种事务间的隔离级别,MySQL都支持:

  1. 读未提交(READ UNCOMMITTED)
  2. 读已提交(READ COMMITED)
  3. 可重复读(REPEATABLE READ)
  4. 串行化(SERIALIZABLE)

从1 - 4隔离强度递增,并发性能递减。MySQL的InnoDB默认的隔离级别是 可重复读(REPEATABLE READ)。

事务的隔离级别是为了解决事务并发中可能会产生的问题:

脏读:

指事务的SELECT读取到了其他事务未提交的数据,如果其他事物回滚,则产生脏读。

可重复读:

指在一个事务内,任意时刻读到的数据都是一致的,例如在同一时刻内,事务A和事务B修改了同一行记录,但是互相的修改不可见,这就是可重复读,通常指的是更新(UPDATE)操作

不可重复读:

与可重复读相反,任意时刻读到的数据不一致,也指更新(UPDATE)操作

幻读:

指事务A中,执行了一次查询,之后事务B又执行了一次插入(INSERT)操作并提交,下一时刻事务A又执行了一次查询,查到了事务B插入的数据,好像发生幻觉一样,就叫做幻读。

 

事务隔离级别就是为了解决上述问题,不同隔离级别下能解决的程度不同,见下表。

隔离级别 脏读 不可重复读 幻读
读未提交 × × ×
读已提交 × ×
可重复读 ×
串行

 

 

 

 

 

 

读未提交串行 由于数据一致性与性能的问题,基本不用,所以本文重点探讨读 已提交 和 可重复读 的实现原理。

 

隔离性探讨要分两个部分来说:

事务之间的隔离,这主要是通过机制来实现的。

事务之间的隔离,这主要是通过mvcC机制实现的。

 

1、写与写的隔离

首先我们来了解下InnoDB解决事务间写与写隔离的锁机制:

事务在修改数据行之前,必须先获得锁才可以操作;获得锁之后,事务便可以操作数据,在此期间其他需要操作此行数据的事务只能阻塞等待,在事务完成或回滚后即可释放锁,让下一个事务继续争夺锁。

表锁与行锁

从锁粒度的角度来说,锁分为行锁与表锁,行锁只会锁定对应行的数据,在此期间其他事物不可修改此行数据;表锁会锁定整个表的数据,在此期间其他任何事务的修改操作都会阻塞,性能极差。

但是由于加锁本身需要消耗资源(获得锁、检查锁、释放锁等),因此在锁定数据较多情况下使用表锁可以节省大量资源。

如下语句可以查看锁信息:

select * from sys.innodb_lock_waits; //8.0之后的语句
select * from infORMation_schema.innodb_locks;

 

 举个例子,以 8.0.18 的MySQL为例:

现有表信息如下,id列是主键字段:

执行以下语句后:

start transaction;
update t set a = 122 where id = 1;

start transaction;
update t set a = 1222 where id = 1;

  可以看到记录添加了一个排它锁(x),锁类型为行锁(record):

 

间隙锁(GAP LOCK)与 临键锁(NEXT-KEY LOCK)

间隙锁与临键锁也可以理解为行锁,只是锁的数据行多了些。

 注意:间隙锁与临键锁只在非唯一索引上有效。

 

 间隙锁基于 非唯一索引,注意:使用间隙锁锁住的是一个区间,而不仅仅是这个区间中的每一条数据。

select * from account where id between 1 and 10 for update;

 

 所有在(1,10)区间内的行都会锁住,所有id 为 2、3、4、5、6、7、8、9 的数据行的插入会被阻塞,但是 1 和 10 两条记录行并不会被锁住。

 间隙锁的锁定范围为索引上命中或未命中的数据行的左最近一个记录和右最近的一行记录的左开右开区间。

例如:

 

 

图中是一个age索引列上的数据,其中,(1,5)、(5,9)、(10,15) 就是间隙,在一个事务内执行如下语句时:

select * from user where age > 5 and age < 9 for update;

 这个时候区间( 5, 9 )是加了间隙锁的,任何其他事务的修改(insert 、update、delete)都被阻塞,无法进行,直到持有锁的事务提交或者回滚释放锁后,其他事务才能执行操作。

 

临键锁在使用非唯一索引进行范围查询,且命中了记录的情况下才会使用,相当于记录锁 + 间隙锁。

临键锁的锁定范围为左开右闭区间,目的是为了解决幻读的问题。

临键锁有两种退化的情况:

如果是唯一性索引,等值查询匹配到一条记录的时候,退化成记录锁。

如果没有匹配到任何记录的时候,退化成间隙锁。

 考虑如下SQL:

select * from user where age > 5 and age < 15;

 

 上面的SQL命中了age = 9的数据,也包含了不存在的记录的区间,所以(5, 9] 和 (10, 15]区间会被同时锁定,这期间别的事务插入不了数据,也更新不了数据。

 

以上介绍的行锁(RECORD LOCK)、间隙锁(GAP LOCK)、临键锁(NEXT KEY LOCK)的使用解决了事务间写与写的隔离性问题,接下来介绍事务间写与读的隔离机制。

 

2. 读与写的隔离

InnoDB解决事务间读写的隔离采用的是MVCC(Multi-Version Concurrency Control)机制,即多版本并发控制协议。

用一个例子来说明MVCC的特点:

同一时刻,不同事务可以读到不同版本的数据,在T5时刻,事务A和C可以读到不同版本的数据。

 

MVCC的优势在于读不加锁,通过对数据行的版本控制实现读写的隔离,并发性能优异。下面我们来深度分析一下MVCC的实现原理。

先来了解几个概念:

隐藏列:InnoDB中每行记录都有隐藏列,包含本行数据当前事务的事务id、指向undo log的指针等。

基于undo log的版本链:隐藏列中包含指向undo log的指针,每条undo log也包含指向前一版本的指针,由此形成了一条版本链。

ReadView:指事务在某一时刻给整个事务系统(trx_sys)打快照,后续读操作会将读取到的数据事务id与快照作比较,借此判断是否数据是否对当前事务可见,如不可见则遍历undo log指针到该数据的前一个版本号。

trx_sys中的主要内容如下:

low_limit_id:表示生成ReadView时事务系统即将分配给下一个事务的事务id,事务系统对事务的id分配是顺序递增的。

up_limit_id:表示生成ReadView时事务系统中活跃的事务中最小的事务id。

rw_trx_ids:表示生成ReadView时活跃的事务id列表。

 

判断可见性的逻辑如下:

如果数据的事务id大于等于low_limit_id,则对该ReadView不可见。

如果数据事务id小于up_limit_id,则对该ReadView可见。

如果数据事务id在low_limit_id和up_limit_id之间,则需要判断事务id是否在rw_trx_ids中,如果在,表明生成ReadView时该事务仍在活跃,所以该数据对ReadView不可见;如果不在,表明生成ReadView时该事务已经提交了,则可见。

 

前面提到MVCC用于解决事务间写与读的隔离性问题,在可重复读(REPEATABLE Read)级别下,MVCC解决了脏读、不可重复读、幻读的问题,下面一一举例来说明。

参考以上表格,事务A与B在同时开始,事务A在T3时刻查询余额,会生成ReadView,此时事务B未提交仍在活跃,因此事务B的id会在rw_trx_ids中,所以事务B的修改对事务A不可见,事务A判断不可见后会根据隐藏列的undo log指针查询前一版本

的数据,得到值为100,这样就避免了读到事务B未提交的数据,避免了脏读

 

 

 

参考以上表格,事务A在T2时刻查询余额,查询执行前会生成ReadView;事务B在T3时刻修改余额,随后提交事务。事务A在T5时刻再次查询了余额,使用首次查询生成的ReadView来判断,此时数据的事务id大于ReadView的low_limit_id,事务A

即从undo log的指针查询前一版本的数据,余额依旧查询为100,避免了不可重复读。

 

 

 参考以上表格,事务A在T2时刻查询数据前会生成一个ReadView;此时事务B在T3时刻插入了一个新用户,且用户主键在事务的查询区间中,事务B可以分两种情况来讨论:

一种是如图中所示,事务已经开始但没有提交,此时其事务id在ReadView的rw_trx_ids中;

 一种是事务B还没有开始,此时其事务id大于等于ReadView的low_limit_id。

无论哪种情况,事务B的修改都是不可见的。

事务A在T5时刻再次读取余额时,会根据首次查询生成的ReadView判断出事务B的修改是不可见的,因此会根据undo log指针查询上一版本的数据,发现上一版本没有数据,不作任何处理,避免了幻读

 

总结

前文介绍了InnoDB事务隔离性的大致实现原理,需要注意的是,MVCC在非加锁读的情况下生效,如果对select语句显式的执行了 for update或for share关键字,InnoDB会采用锁的形式来控制隔离。

在读已提交和可重复读的MVCC实现中对ReadView的生成是有些区别的,读已提交在每次Select都会重新生成ReadView,从而实现对已提交的事务数据的可见,可重复读则只会在事务首次Select时生成ReadView,从而保证

事务生命周期中对其他事务的修改的完全隔离。

 

四、一致性


一致性的实现其实是基于前文所提及的原子性、持久性和隔离性,换句话说,只有保证了原子性、持久性与隔离性,才能保证一致性。

此外,应用层面的一致性保证也是需要的,例如常见的转账操作,扣减库存等,需要引用层面的并发控制机制来实现。

 

 

结语:


 

本文是对近期MySQL学习的总结和梳理,受本人水平所限,难免有出入之处,烦请各位读者不吝赐教。

参考文献:

https://www.cnblogs.com/kismetv/p/10331633.html

Https://segmentfault.com/a/1190000040129107

原文地址:https://www.cnblogs.com/kimyoung/arcHive/2022/03/15/16007636.html

您可能感兴趣的文档:

--结束END--

本文标题: MySQL事务ACID原理深度解析

本文链接: https://www.lsjlt.com/news/9187.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • MySQL事务ACID原理深度解析
    什么是MySQL事务? 事务是指对数据库的一组操作的集合,集合中的SQL语句要么全部执行成功,要么就全部失败,如果集合中任一操作出错,则此集合所有对数据库的操作全部回滚。 以常见的购物操作举例,用户下单后要执行订单创建、减库存等一系列操...
    99+
    2018-05-21
    MySQL事务ACID原理深度解析
  • MySql事务及ACID实现原理详解
    目录逻辑架构和存储引擎自动提交特殊操作ACID 特性原子性持久性隔离性脏读、不可重复读和幻读事务隔离级别MVCC一致性逻辑架构和存储引擎 自动提交 MySQL 中默认采用的是自动提...
    99+
    2022-11-13
  • 深入解析MySQL 事务
    目录事务的四大特性 ( ACID )脏读不可重复读幻读MySQL的隔离级别事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。 事务的四大特性 ( ACID ...
    99+
    2022-11-13
  • mysql 间隙锁原理深度详解
    目录 一、前言 二、mysql之mvcc 2.1 什么是mvcc 2.2 mvcc组成 2.2.1 Undo log 多版本链 2.2.2 ReadView 2.2.3 快照读与当前读 三、RR级别下的事务问题 3.1 RR隔离级别解决的问...
    99+
    2023-08-31
    mysql间隙锁 间隙锁 mysql可重复读
  • Spring Boot 底层原理基础深度解析
    目录1. 底层注解@Configuration2. 底层注解@Import3. 底层注解@Conditional1. 底层注解@Configuration @Configuratio...
    99+
    2022-11-13
  • 一文快速搞懂MySQL InnoDB事务ACID实现原理
    【51CTO.com原创稿件】说到数据库事务,想到的就是要么都做修改,要么都不做,或者是 ACID 的概念。其实事务的本质就是锁、并发和重做日志的结合体。 这一篇主要讲一下 InnoDB 中的事务到底是如何...
    99+
    2022-10-18
  • MySQL事务之ACID特性的实现原理是什么
    小编给大家分享一下MySQL事务之ACID特性的实现原理是什么,希望大家阅读完这篇文章后大所收获,下面让我们一起去探讨吧!事务是MySQL等关系型数据库区别于NoSQL的重要方面,是保证数据一致性的重要手段...
    99+
    2022-10-18
  • Spring事务原理解析
    目录前言问题描述代码复现排查1. 锁失效2. 事务隔离级别3. 修改Spring事务传播配置解决方案前言 最近在编写公司APP产品的商品砍价功能,其中有一个接口涉及并发访问。自测时通...
    99+
    2022-12-20
    Spring事务管理机制 Spring事务管理方式 Spring事务底层
  • Mysql事务特性和级别原理解析
    一、什么是事务? 数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。 二、事务的四大属性 分别是原子性、一致性、隔离性、持久性。 1、原子性(Atomicity) ...
    99+
    2022-05-19
    Mysql 事务特性 级别
  • MySQL数据库本地事务原理解析
    在经典的数据库理论里,本地事务具备四大特征: 原子性 事务中的所有操作都是以原子的方式执行的,要么全部成功,要么全部失败; 一致性 事务执行前后,所有的数据都应该处于一致性状态---...
    99+
    2022-11-13
  • 深入解析MySQL MVCC 原理与实现
    深入解析MySQL MVCC 原理与实现MySQL是目前最流行的关系型数据库管理系统之一,它提供了多版本并发控制(Multiversion Concurrency Control,MVCC)机制来支持高效并发处理。MVCC是一种在数据库中处...
    99+
    2023-10-22
    原理 MySQL mvcc
  • Mysql事务隔离级别原理实例解析
    引言 大家在面试中一定碰到过 说说事务的隔离级别吧? 老实说,事务隔离级别这个问题,无论是校招还是社招,面试官都爱问!然而目前网上很多文章,说句实在话啊,我看了后我都怀疑作者弄懂没!因为他们对可重复读(Repeata...
    99+
    2022-05-29
    Mysql 事务 隔离 级别
  • MySQL索引长度限制原理解析
    这篇文章主要介绍了MySQL索引长度限制原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 索引 TextField是不支持建立索引的 MySQL对...
    99+
    2022-10-18
  • Spring底层事务原理解析
    目录一、@EnableTransactionManagement工作原理二、Spring事务基本执行原理四、Spring事务传播机制五、Spring事务传播机制分类六、Spring事...
    99+
    2022-12-10
    Spring底层事务原理 Spring底层事务 Spring底层原理
  • 深度源码解析Java 线程池的实现原理
    目录线程池的优点线程池的实现原理ThreadPoolExecutor阻塞队列线程池工厂拒绝策略提交任务到线程池execute 方法submit 方法关闭线程池合理的参数7、本文小结j...
    99+
    2022-11-12
  • 深入理解Spring事务及传播机制之原理解析与实际应用
    目录事务概述事务管理事务传播机制事务传播机制实现框架源码解析总结Spring 框架是一个流行的Java应用程序框架,其中事务管理是其最重要的特性之一。事务是指一系列相关操作的集合,如...
    99+
    2023-05-16
    Spring事务及传播机制 Spring事务管理 Spring传播机制
  • 教你如何深度解析Windows7的设备驱动管理原理
    1、Windows 7系统的设备驱动文件解读 在Windows7系统中包含了一个覆盖范围很广的身边驱动程序库。在该操作系统的基本安装中,这些驱动程序都会保存在驱动程序存储区中,它们位于%SystemRoot%\Syste...
    99+
    2023-05-25
    设备驱动 驱动管理 Windows7 设备 管理 驱动 深度
  • 深入理解mysql事务与存储引擎
    目录一、MySQL事务1、事务的概念2、事务的 ACID 特点3、事物之间的互相影响二、Mysql及事务隔离级别1、查询全局事务隔离级别2、查询会话事务隔离级别3、设置全局事务隔离级...
    99+
    2022-11-13
  • 深入解析MySQL索引的原理与优化策略
    目录索引的概念索引的原理索引的类型索引的使用索引的使用方式注意事项索引优化技巧索引的概念 mysql索引是一种用于加速数据库查询的数据结构,它类似于书籍的目录,能够快速指导我们找到需要的信息。MySQL索引可以根据一定的...
    99+
    2023-03-31
    解析MySQL索引原理和优化策略 MySQL索引原理 MySQL优化策略
  • MySql 知识点之事务、索引、锁原理与用法解析
    本文实例讲述了MySql 知识点之事务、索引、锁原理与用法。分享给大家供大家参考,具体如下: 事务 事务概念 事务就是一组原子性的SQL查询,或者说一个独立的工作单元。如果数据库引擎执行一组操作语句...
    99+
    2022-10-18
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作