滴滴滴,请看MYSQL事务的四大特征(ACID)的实现原理:晓其原理而通其实现。

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 滴滴滴,请看MYSQL事务的四大特征(ACID)的实现原理:晓其原理而通其实现。

一.什么是事务的四特征

  • 原子性(Atomicity,或称不可分割性)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)

接下来,我们将对四大特性的具体概念以及其底层实现原理来进行剖析:

在讲述具体的四大特性之前,我们先补充一点前置知识 :

1.逻辑架构和存储引擎

877a0f064893417ea191e3c5b74d8b69.png

如上图,我们可以将mysql服务器的逻辑架构整体分为三层:


①第一层:负责客户端的连接和授权认证等


②第二层:服务器层:负责查询语句的解析,优化以及缓存,内置函数的实现和存储等


③第三层:存储引擎:负责数据库中数据的存储和读取,mysql服务器层不管理事务,事务是由存储引擎实现的。其中支持事务的存储引擎有innoDB和NDB Cluster等,其中比较应用广泛的是innoDB。


我们进行四大特性的具体介绍:

一.原子性

56b9561b6e314aafbc824a5feb33a9b3.png

1. 定义

原子性是指一个事务是一个不可分割的工作单位,其中的操作要么都做,要么都不做;如果事务中一个sql语句执行失败,则已执行的语句也必须回滚,数据库退回到事务前的状态。


2.实现原理:redolog

在具体讲述redolog日志之前,我们先对mysql中存在的事务日志进行解释:mysql中存在很多类型的事务日志:包括二进制日志,错误日志以及查询日志等。除此之外,innoDB还提供了两个的日志:undolog(回滚日志) 和redolog(重做日志),其中undolog是数据的原子性和一致性的重要保证,而redolog用于保证事务的持久性。


UNDOLOG


undolog是实现事务原子性的重要保证,undolog能使一个事务中已经执行成功的所有sql语句进行回滚操作,其具体的工作流程如下:当事务修改数据库中的数据时,innoDB会对应生成具体的UNDO log ,一旦事务执行失败或者触发rollback操作时,就能使用redolog中的信息对数据库修改之前的数值进行恢复。


undolog是一种逻辑性日志,在触发rollback或者事务执行失败时,innoDB会根据undolog中记录的信息对数据库进行相反方向的操作,比如:之前的操作时insert语句,这时调用执行delete语句;如果之前执行的update语句,则会执行反方向的update语句。


二.持久性

cb7c1999ab284067ba1cb6fabfa0bc8e.png

1. 定义

持久性是指事务一旦提交,它对数据库的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。


2.实现原理

redolog


在进行事务持久性的讲述之前,我们首先来说一下redolog存在的背景以及其存在的必要性:


对数据库的读写操作是对数据库中的数据进行操作,也就是说需要对数据库进行IO操作,但是对数据库频繁的IO效率很低,为此,innoDB提供了缓存层(BufferPool),BufferPool中储存着数据库部分数页的映射,作为数据库数据的缓冲:当我们需要从数据库汇总读入数据时,这时我们先从BufferPool中查找,在BufferPool中找不到,这时候从数据库中获取数据然后将其放入BufferPool,往数据库中写入数据也是先将数据写入到BufferPool,然后定期刷新到磁盘中(这一过程称为脏刷)。


但是带来便利的同时也存在一定的风险和弊端,如果在某刻数据库突然宕机,而这时在BufferPool中仍存在数据或者修改的数据没有刷入磁盘中,必然会导致数据丢失的问题,也无法保证数据的持久性,为了解决这个问题,redolog日志应运而生。redolog同样也是innoDB中的日志,它的实现原理如下:当数据写入到BufferPool之前或者对BufferPool中的数据进行修改之前,首先会先在redolog中记录此次操作,当事务提交时,会使用fsync接口对redolog进行刷盘,而如果数据库发生宕机问题,数据库会读取redolog中的信息,对数据库的数据进行恢复。redo log采用的是WAL(Write-ahead logging,预写式日志),所有数据在写入BufferPoo或者在BufferPool中修改数据之前,都会先写入redolog ,保证了数据不会因mysql宕机而丢失,从而保证了数据的持久性。


那么既然redolog也是在数据提交时将数据写入数据库,那么它为什么比通过BufferPool写入数据库的效率要高呢?


主要是以下两方面的原因:


1.redolog是顺序IO,而BufferPool是随机IO,进行数据读写的位置随机生成,速度相对顺序IO较慢


2.BufferPool写入数据的方式是以一个数据页为单位,一般mysql的page大小为为16kb,而一旦一个页有任何数据的修改,都需要整页数据重写写入,而redolog是真正的有效写入:只写入新添加的或者修改的数据,无效IO大大减少。


三.隔离性

7cfac908a077416f9740e9d1e9fca42f.png

1.定义:

隔离性是研究事务之间的相互影响,隔离性是指事务内部的操作和其他事务之间是隔离的,在并发环境中,各个事务互不干扰,严格的隔离性,对应了事务隔离级别中的Serializable (可串行化),但实际应用中出于性能方面的考虑很少会使用可串行化。

2.实现原理

隔离性追求的是并发事务中彼此之间不相互影响,而在我们日常的操作中最主要考虑的是读操作和写操作:

1.一个写操作对另一个写操作的影响:通过锁机制进行解决


2.一个写操作对另一个读操作的影响:通过MVCC机制进行解决

1.锁机制:在写操作要求中,在同一时间只能允许一个事务对同一部分数据进行写操作,innoDB实现的锁机制的实现原理可以这样理解:事务在对数据进行写操作之前,要先获取锁资源,然后此时才能对数据进行写操作,其他事务想要获取锁资源必须等待当前事务进行事务的回滚或者提交写操作之后释放锁。

行锁和表锁:按照锁的粒度,可以将锁分为行锁和表锁以及介于两者之间的锁,表锁是在事务进行操作数据时锁定整张表,进行数据的操作时并发性能差,而行锁是在事务操作数据时只锁定被操作的数据,并发性能好,但是考虑到锁的创建,检查以及销毁都需要消耗资源,所以一般而言,表锁相对于行锁能节省部分资源,但是考虑到业务和性能需求,所以在一般情况下都使用行锁,但是sql中不同的存储引擎对表锁和行锁的支持也有所不同,对于innoDB而言,其支持行锁和表锁。


有关事务的隔离性以及不同隔离性可能会产生的问题,推荐大家看我另一篇文章,在这里就不进重复的赘述了:


关于对事务隔离性的深入理解_努力努力再努力mlx的博客-CSDN博客


2.MVCC机制:在sql的隔离级别中默认的隔离级别是可重复读(Repeatly Read),一般而言,RR不能解决幻读的问题,但是innoDB实现的RR能够避免幻读问题的产生,RR解决脏读、不可重复读、幻读等问题,使用的是MVCC:MVCC全称Multi-Version Concurrency Control,即多版本的并发控制协议。MVCC具有以下特点:在同一时间,不同事务所读取的数据可能是不同的(不同的版本中的数据不同),如下图能比较好的体现这一特点:在T5时刻,事务A和事务C可以读取到不同版本的数据。


1e80de129d1e4770a43c96c29e867de8.png

MVCC最大的好处是可以不加读锁,因此读写不冲突,而innoDB实现的MVCC,可以允许多个版本共存,其功能的实现主要是基于以下的技术和 数据结构:

1.隐藏列:数据库中的每条数据都有隐藏列,隐藏列有指向本行数据事务的id和指向undolog的指针


2.基于undolog的版本链:每条数据的隐藏列中都有指向undolog的指针,而每条undolog的指针也会指向更早版本的undolog,从而形成一条undolog版本链


3.ReadView:通过隐藏列和版本链,能将数据恢复到之前的版本,但是具体要恢复到哪个版本,则需要具体的ReadView来确定。所谓的ReadView ,是指事务(事务A)在某一时刻对整个事务系统(trx_sys)打快照,等之后再进行读操作时,会将读取到的事务id和trx_sys作比较,从而判断想读取的数据对该ReadView是否有效,即对事务A是否有效。


trx_sys中的主要内容,以及判断可见性的规则如下:


low_limit_id:表示生成的ReadView 中系统应分配给事务的下一个id.如果事务的id大于等于该low_limit_id,则对该ReadView不可见。


up_limit_id:表示在生成ReadView时在系统中活跃的事务,如果活跃事务的id小于up_limit_id,,则对该ReadView 可见


rw_trx_ids:表示在生成ReadView时在系统中活跃事务的id列表,如果查询数据的id在low_limit_id和up_limit_id之间,则需要看事务是否在rw_trx_ids中,如果在,则说明生成ReadView时事务仍在活跃中,则对该ReadView不可见,如果不在,说明生成ReadView时事务已经提交了,因此数据对ReadView可见。


3.MVCC是如歌规避脏读、不可重复读和幻读等问题的呢?

3.1脏读:

dad4d9f9dbdc498ebe9394cf63b71bb3.png

当事务A在T3时刻读取zhangsan的余额前,会生成ReadView,由于此时事务B没有提交仍然活跃,因此其事务id一定在ReadView的rw_trx_ids中,因此根据前面介绍的规则,事务B的修改对ReadView不可见。接下来,事务A根据指针指向的undo log查询上一版本的数据,得到zhangsan的余额为100。这样事务A就避免了脏读。


3.2不可重复读

177eb7856e8248f38b72079e43d02c8a.png

当事务A在T2时刻读取zhangsan的余额前,会生成ReadView。此时事务B分两种情况讨论,一种是如图中所示,事务已经开始但没有提交,此时其事务id在ReadView的rw_trx_ids中;一种是事务B还没有开始,此时其事务id大于等于ReadView的low_limit_id。无论是哪种情况,根据前面介绍的规则,事务B的修改对ReadView都不可见。


当事务A在T5时刻再次读取zhangsan的余额时,会根据T2时刻生成的ReadView对数据的可见性进行判断,从而判断出事务B的修改不可见;因此事务A根据指针指向的undo log查询上一版本的数据,得到zhangsan的余额为100,从而避免了不可重复读。


3.3幻读

12650220e821499380530fb15f8e8791.pngMVCC避免幻读的机制与避免不可重复读非常类似。


当事务A在T2时刻读取0<id<5的用户余额前,会生成ReadView。此时事务B分两种情况讨论,一种是如图中所示,事务已经开始但没有提交,此时其事务id在ReadView的rw_trx_ids中;一种是事务B还没有开始,此时其事务id大于等于ReadView的low_limit_id。无论是哪种情况,根据前面介绍的规则,事务B的修改对ReadView都不可见。


当事务A在T5时刻再次读取0<id<5的用户余额时,会根据T2时刻生成的ReadView对数据的可见性进行判断,从而判断出事务B的修改不可见。因此对于新插入的数据lisi(id=2),事务A根据其指针指向的undo log查询上一版本的数据,发现该数据并不存在,从而避免了幻读。


加锁读在查询时会对查询的数据加锁(共享锁或排它锁)。由于锁的特性,当某事务对数据进行加锁读后,其他事务无法对数据进行写操作,因此可以避免脏读和不可重复读。而避免幻读,则需要通过next-key lock。next-key lock是行锁的一种,实现相当于record lock(记录锁) + gap lock(间隙锁);其特点是不仅会锁住记录本身(record lock的功能),还会锁定一个范围(gap lock的功能)。因此,加锁读同样可以避免脏读、不可重复读和幻读,保证隔离性。

四.一致性

96e18c449383422986e714a739dceb62.png

1.概念:致性是指事务执行结束后,数据库的完整性约束没有被破坏,事务执行的前后都是合法的数据状态。

2.实现:一致性是数据库最终追求的目的,原子性,隔离性和持久性,都是为了满足一致性而存在的,除了数据库层面用于保证数据的一致性,一致性的实现在应用层也有所保障。

实现一致性的措施:

1.使用原子性,持久性和隔离性保证一致性,如果这三个特征无法保证,一致性也无法保证

2.数据库本身做出保障,例如不允许向整形数据中插入字符串信息,字符串的长度不允许超过列的最大长度

3.应用层面进行保障,例如如果转账操作只扣除转账者的余额,而没有增加接收者的余额,无论数据库实现的多么完美,也无法保证状态的一致性

五.总结:

原子性:语句要么全执行,要么全不执行,是事务最核心的特性,事务本身就是以原子性来定义的;实现主要基于undo log

持久性:保证事务提交后不会因为宕机等原因导致数据丢失;实现主要基于redo log

隔离性:保证事务执行尽可能不受其他事务影响;InnoDB默认的隔离级别是RR,RR的实现主要基于锁机制(包含next-key lock)、MVCC(包括数据的隐藏列、基于undo log的版本链、ReadView)

一致性:事务追求的最终目标,一致性的实现既需要数据库层面的保障,也需要应用层面的保障


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
19天前
|
存储 SQL 关系型数据库
MySQL进阶突击系列(03) MySQL架构原理solo九魂17环连问 | 给大厂面试官的一封信
本文介绍了MySQL架构原理、存储引擎和索引的相关知识点,涵盖查询和更新SQL的执行过程、MySQL各组件的作用、存储引擎的类型及特性、索引的建立和使用原则,以及二叉树、平衡二叉树和B树的区别。通过这些内容,帮助读者深入了解MySQL的工作机制,提高数据库管理和优化能力。
|
23小时前
|
SQL 关系型数据库 MySQL
MySQL事务日志-Undo Log工作原理分析
事务的持久性是交由Redo Log来保证,原子性则是交由Undo Log来保证。如果事务中的SQL执行到一半出现错误,需要把前面已经执行过的SQL撤销以达到原子性的目的,这个过程也叫做"回滚",所以Undo Log也叫回滚日志。
MySQL事务日志-Undo Log工作原理分析
|
10天前
|
SQL 安全 关系型数据库
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
|
16天前
|
SQL 关系型数据库 MySQL
MySQL进阶突击系列(04)事务隔离级别、AICD、CAP、BASE原则一直搞不懂? | 看这篇就够了
本文详细介绍了数据库事务的四大特性(AICD原则),包括原子性、隔离性、一致性和持久性,并深入探讨了事务并发问题与隔离级别。同时,文章还讲解了分布式系统中的CAP理论及其不可能三角关系,以及BASE原则在分布式系统设计中的应用。通过具体案例和图解,帮助读者理解事务处理的核心概念和最佳实践,为应对相关技术面试提供了全面的知识准备。
|
20天前
|
缓存 关系型数据库 MySQL
MySQL 索引优化与慢查询优化:原理与实践
通过本文的介绍,希望您能够深入理解MySQL索引优化与慢查询优化的原理和实践方法,并在实际项目中灵活运用这些技术,提升数据库的整体性能。
51 5
|
1月前
|
SQL 存储 关系型数据库
MySQL进阶突击系列(01)一条简单SQL搞懂MySQL架构原理 | 含实用命令参数集
本文从MySQL的架构原理出发,详细介绍其SQL查询的全过程,涵盖客户端发起SQL查询、服务端SQL接口、解析器、优化器、存储引擎及日志数据等内容。同时提供了MySQL常用的管理命令参数集,帮助读者深入了解MySQL的技术细节和优化方法。
|
2月前
|
关系型数据库 MySQL 数据库
MySQL事务隔离级别及默认隔离级别的设置
在数据库系统中,事务隔离级别是一个关键的概念,它决定了事务在并发执行时如何相互隔离。MySQL提供了四种事务隔离级别,每种级别都解决了不同的并发问题。本文将详细介绍这些隔离级别以及MySQL的默认隔离级别。
|
12天前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
39 3
|
12天前
|
安全 关系型数据库 MySQL
MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!
《MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!》介绍了MySQL中的三种关键日志:二进制日志(Binary Log)、重做日志(Redo Log)和撤销日志(Undo Log)。这些日志确保了数据库的ACID特性,即原子性、一致性、隔离性和持久性。Redo Log记录数据页的物理修改,保证事务持久性;Undo Log记录事务的逆操作,支持回滚和多版本并发控制(MVCC)。文章还详细对比了InnoDB和MyISAM存储引擎在事务支持、锁定机制、并发性等方面的差异,强调了InnoDB在高并发和事务处理中的优势。通过这些机制,MySQL能够在事务执行、崩溃和恢复过程中保持
42 3
|
12天前
|
SQL 关系型数据库 MySQL
数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog
《数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog》介绍了如何利用MySQL的二进制日志(Binlog)恢复误删除的数据。主要内容包括: 1. **启用二进制日志**:在`my.cnf`中配置`log-bin`并重启MySQL服务。 2. **查看二进制日志文件**:使用`SHOW VARIABLES LIKE &#39;log_%&#39;;`和`SHOW MASTER STATUS;`命令获取当前日志文件及位置。 3. **创建数据备份**:确保在恢复前已有备份,以防意外。 4. **导出二进制日志为SQL语句**:使用`mysqlbinlog`
54 2