MySQL数据库本地事务原理解析

在经典的数据库理论里,本地事务具备四大特征:

  • 原子性

事务中的所有操作都是以原子的方式执行的,要么全部成功,要么全部失败;

  • 一致性

事务执行前后,所有的数据都应该处于一致性状态---即要满足数据库表的一致性约束,也要达到业务一致性(完成了业务目标);

  • 隔离性

并发执行的事务不应该相互干扰;隔离性的强度由隔离级别决定;

  • 持久性

事务一旦被提交,它添加/修改的数据不会随着系统崩溃而丢失;

在MySQL(InnoDB引擎)中,原子性和持久性是通过Redo Log来实现的,一致性是通过Undo Log实现的,而隔离性则是通过锁和MVCC来实现的。

ARIES算法

如果需要深入了解数据库本地事务原理,不得不提到ARIES算法,该算法全称为Algorithms for Recovery and Isolation Exploiting Semantics(基于语义的恢复与隔离算法),众多主流的关系型数据库都受到该算法的影响。

ARIES算法主要针对使用No Force + Steal的数据写入策略而采用的一种数据恢复方式。

该算法主要基于三个主要的原则:

  • Write-ahead logging

出于性能上的考虑,数据的修改都是在内存中进行,并将这些“修改操作”记录到日志(Redo Log和Undo Log)中,然后异步将内存中的数据写入到磁盘;

  • 通过Redo Log恢复数据

Redo Log用于记录事务对数据的修改操作,在数据库崩溃恢复时,ARIES通过Redo Log重放那些还未写入到数据库磁盘中的数据操作,将数据恢复至崩溃前的状态;

  • 通过Undo Log回滚数据

对崩溃前未提交的事务,通过Undo Log进行回滚;

Write-ahead logging

每个事务执行时,都是在内存中进行数据的修改,并将这些“修改操作”记录到日志,然后将内存中的数据异步写入到磁盘里;

但日志也并非立刻写入至磁盘,而是先写入到Log Buffer,再按照相应的参数配置进行磁盘的写入操作;在写入至磁盘时,数据会先写入至操作系统内核缓冲区(OS Buffer),然后根据参数配置决定对内核缓冲区中的数据同步或异步刷盘。

如在InnoDB中,Redo Log的磁盘写入策略是由innodb_flush_log_at_trx_commit参数值来决定的:

0: 当参数值设置为0时,每隔1秒将Redo Log Buffer中的数据写入至OS Buffer,并同时调用fsync()函数完成刷盘操作;

1: 每次事务提交时,立即将Redo Log Buffer中的数据写入至OS Buffer,并同时调用fsync()函数完成刷盘操作;

2: 每次事务提交时,立即将Redo Log Buffer中的数据写入至OS Buffer,每隔1秒调用fsync()函数完成刷盘操作;

由此可见,当innodb_flush_log_at_trx_commit设置为0或2时,都会导致日志数据丢失;

以上讨论了“数据操作”日志的写入方式,而对于事务中真正修改的数据,Write-ahead logging根据事务提交的时间节点,将变动的数据写入至磁盘的时间节点分为Force和Steal两种:

Force:在事务提交时,是否强制将变动的数据完全写入至磁盘?

Steal:在事务提交前,是否允许将变动的数据提前写入至磁盘?

因此根据Force和Steal的值,数据的写入策略可以分为以下四种:

Steal No Steal
Force
事务提交时,强制将变动数据完全写入至磁盘

事务提交前,允许将变动的数据提前写入至磁盘


事务提交时,强制将变动数据完全写入至磁盘

事务提交前,不允许变动的数据提前写入至磁盘

No Force
事务提交时,不需要强制变动数据完全写入至磁盘

事务提交前,允许将变动的数据提前写入至磁盘


事务提交时,不需要强制变动数据完全写入至磁盘

事务提交前,不允许变动的数据提前写入至磁盘

直观感觉就可以知道,采用No Force + Steal的方式,不需要在事务提交时,强制将所有的变动数据写入至磁盘,同时允许变动的数据在事务提交前即可提早写入至磁盘;这样的写入策略灵活性强且性能最好;MySQL InnoDB采用的就是此种写入方式。

Redo Log

Physiological Logging

在崩溃并重启后,数据库重放Redo Log进行数据恢复时,由于并不知道崩溃前哪些变动的数据已经写入到物理磁盘,因此需要保证Redo Log的重放是幂等的,即多次重放得到的结果不会改变;

InnoDB中所有的数据都是以数据页(Page)的形式存在于磁盘中的,因此Redo Log中的每一条日志,会记录被修改的数据页Page ID、被修改的记录在该Page中的位移、记录中哪些字段被修改了、修改后的字段值:

(Page ID,Record Offset,(Filed 1, Value 1) … (Filed i, Value i) … )

一个事务可能修改多条记录(这些记录可能位于同一个数据页,也可能位于不同的数据页),就会产生多条日志;同时数据库的多个事务都是并行执行的,出于性能的考虑,它们在Redo Log中并非以串行的方式写入,而是多个事务产生的多条日志互相穿插在Redo Log中,这就导致了Mini Transaction(Mtr)的产生。Mtr是数据库事务在Redo Log中的最小存储单元,一个数据库事务被划分为一个或多个Mtr,一个Mtr仅包含对一个数据页的修改(由于一个数据页可能包含多条记录,因此一个Mtr中包含的日志记录也不止一条)。

虽然同一个事务的多个Mtr在Redo Log中可能是不连续的,但同一个Mtr中包含的多条日志在Redo Log中一定是连续的。

我们把Redo Log这样的的存储方式称之为Physiological Logging。

LSN机制

Redo Log不是一个无限膨胀的日志文件,它具有固定的长度,日志先按照物理顺序一直往后添加,当达到空间限制后跳转到开始位置重新进行写操作/覆盖。

Redo Log中的记录也并非永远具有存在的价值,当事务所操作的数据已经被写入到物理磁盘中,这个事务对应的日志就没有存在的意义,事实上是可以被删除了。

MySQL数据库使用CheckPoint的值来指定日志文件可以擦除的位置,也就是说该位置之前的日志都是可以删除的;CheckPoint的值用LSN来表示。

LSN(Log Sequence Number)并非物理位置,它是一个8字节(64位)的整数且单调递增,代表着自数据库启动以来,至当前时间点写入至Redo Log中数据的总量(字节数)。

Redo Log中的每一条日志也使用LSN作为它的标识。

Double Write Buffer

上文谈到数据库通过异步的方式将修改的数据写入至物理磁盘,但如果无法保证数据写入到物理磁盘的原子性,当恰好写入了部分数据后发生崩溃,这会导致物理磁盘中存在一个被损坏的数据页;而Redo Log只记录哪些数据页被修改,但不会记录哪些数据页被损坏,因此无法通过Redo Log来修复这些被损坏的数据页;

MySQL InnoDB使用Double Write Buffer来解决写数据至物理磁盘时崩溃后数据页的恢复问题;

Double Write Buffer是一个存储区,当InnoDB尝试写数据页至物理磁盘之前,会先将数据页写入至该区域;如果写数据时崩溃,恢复时InnoDB可以从Double Write Buffer中找到这个被损坏的数据页的完整副本。

正如名称Double Write所示,这会导致两次磁盘写操作:一次是写入到Double Write Buffer,另外一次是写入到真正的数据页所在的磁盘位置。

另外一个问题:如果日志从Redo Log Buffer写入至磁盘时,数据库崩溃了该如何处理?

Redo Log写入至磁盘是通过日志块(Log Block)的方式进行写入的,日志块不同于内存中的数据页(1 Page = 16 KB),一个日志块的大小为512 Byte。每个日志块中包含该块的摘要值(CheckSum),通过该摘要值可判断写入至磁盘的这个日志块是否完整。

当innodb_flush_log_at_trx_commit设置为2时,事务的提交是以日志写入磁盘作为结束标志的,如果写入时崩溃,则代表事务提交失败,该日志块实际上可以直接丢弃。

Undo Log

在上文Redo Log的Physiological Logging中谈到,Redo Log只会记录某个数据字段修改后的值,在数据库崩溃后恢复阶段会利用Redo Log对事务中的数据操作进行重放,其中包括已提交的事务和未提交的事务;对于那些未被提交的事务,需要使用Undo Log对其进行回滚操作;

与Redo Log使用的Physiological Logging格式不同,Undo Log保存的是逻辑日志;如果事务执行的是一个INSERT操作,Undo Log会保存一条DELETE操作;如果事务中执行的是一个DELETE操作,Undo Log会保存一条INSERT操作;如果事务执行的是一条UPDATE操作,Undo Log中会保存一条反向的UPDATE操作......

Crash Recovery(崩溃恢复)

CheckPoint机制

InnoDB使用了一个叫做Fuzzy Checkpointing的CheckPoint机制来实现数据页写入至磁盘;它并非一次性的将所有内存中的数据页全部写入到磁盘中,因为这会阻塞在写入时其他的数据库操作,因此它采用小批量(Small batches)写入。

当数据库崩溃时,并非所有Redo Log中的事务(包括已提交和未提交的)所修改的数据页都已经写入到了物理磁盘中,我们把那些还未写入的数据页叫做脏页(Dirty Pages)。

在崩溃恢复时,需要找到所有的这些脏页,并利用Redo Log进行重放,也需要找出所有未提交的事务,利用Undo Log进行回滚。

由于Fuzzy Checkpointing只是小批量写入,因此并非所有已提交事务的数据页都写入至磁盘中;同时由于多个事务(包括已提交和未提交的)会修改同一个数据页,这会导致在数据页写入时可能将未提交事务的数据也写入到磁盘中了;所以在每一次Fuzzy Checkpointing之后,会把该次Fuzzy Checkpointing时未提交的事务列表和脏页列表形成为一个CheckPoint日志,保存到Redo Log中。

在崩溃恢复过程中,InnoDB引擎会找到Redo Log中最近一次CheckPoint日志,获取到未提交的事务列表和脏页列表,并以该日志为起点遍历至Redo Log末尾;在遍历过程中,如果遇到事务提交,将其从未提交事务列表中移除,如果遇到新事务开始,将它加入到未提交事务列表;同时对遍历到的所有Physiological Log,都添加到脏页列表;最后会形成一个最终的未提交事务列表和脏页列表。

对脏页列表,在Redo Log中找到最早的那个脏页所对应的日志,并以此为起点进行Redo Log重放。此时可能会遇到的Redo Log对应的数据页实际已经写入至磁盘中了,不过即使再次重放也没有关系,因为Redo Log是幂等的。

对所有未提交的事务列表,找到其对应的Undo Log,并进行回滚操作。

到此这篇关于MySQL数据库本地事务原理的文章就介绍到这了,更多相关MySQL数据库事务原理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • MySQL 数据库 索引和事务

    目录 1. 索引 1.1 概念 1.2 作用 1.3 索引的原理 1.3.1 减少磁盘的访问次数是构建索引的核心思想 1.3.2 B+ 树适用实现索引的底层 1.4 适用场景 1.5 使用语句 1.5.1 查看索引 1.5.2 创建索引 1.5.3 删除索引 2. 事务 2.1 概念 2.2 为什么使用事务 2.3 四大属性 2.3.1 原子性 2.3.2 一致性 2.3.3 持久性 2.3.4 隔离性 2.4 使用方法 1. 索引 1.1 概念 索引是为了加速对表中数据行的检索而创建的一种分散

  • MySQL数据库事务transaction示例讲解教程

    目录 1.什么是事务? 2.和事务相关的语句只有这3个DML语句:insert.delete.update 3.假设所有的业务都能使用1条DML语句搞定,还需要事务机制吗? 4.事务的原理 5.事务的四大特性:ACID 6.关于事务之间的隔离性 1)第一级别:读未提交(read uncommitted) 2)第二级别:读已提交(read committed) 3)第三级别:可重复读(repeatable read) 4)第四级别:序列化读/串行化读(serializable) 7.演示事务的隔离

  • MySQL数据库的事务和索引详解

    目录 一.事务: 事务四大特性: 并发事务带来哪些问题?(隔离所导致的一些问题) 事务隔离级别有哪些? MySQL的默认隔离级别: 二.索引: 索引的作用: 索引的分类: 索引准则: 索引的数据结构: 总结 一.事务: 事务是逻辑上的一组操作,要么都成功,要么都失败! ---------------------------------- 1.SQL执行        A:1000元     -->转账200元        B:200元 2.SQL执行        A:800元       -

  • MySQL数据库事务与锁深入分析

    一.基本概念 事务是指满足ACID特性的的一组操作,可以通过Commit提交事务,也可以也可以通过Rollback进行回滚.会存在中间态和一致性状态(也是真正在数据库表中存在的状态) 二.ACID Atomicity[原子性]:事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚.回滚可以用回滚日志(undo Log)来实现,回滚日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作即可 undoLog:为了满足事务的原子性,在操作任何数据之前,首先将数据备份到U

  • MySQL数据库本地事务原理解析

    在经典的数据库理论里,本地事务具备四大特征: 原子性 事务中的所有操作都是以原子的方式执行的,要么全部成功,要么全部失败: 一致性 事务执行前后,所有的数据都应该处于一致性状态---即要满足数据库表的一致性约束,也要达到业务一致性(完成了业务目标): 隔离性 并发执行的事务不应该相互干扰:隔离性的强度由隔离级别决定: 持久性 事务一旦被提交,它添加/修改的数据不会随着系统崩溃而丢失: 在MySQL(InnoDB引擎)中,原子性和持久性是通过Redo Log来实现的,一致性是通过Undo Log实

  • MySQL数据库锁机制原理解析

    在并发访问情况下,很有可能出现不可重复读等等读现象.为了更好的应对高并发,封锁.时间戳.乐观并发控制(乐观锁).悲观并发控制(悲观锁)都是并发控制采用的主要技术方式. 锁分类 ①.按操作划分:DML锁,DDL锁 ②.按锁的粒度划分:表级锁.行级锁.页级锁 ③.按锁级别划分:共享锁.排他锁 ④.按加锁方式划分:自动锁.显示锁 ⑤.按使用方式划分:乐观锁.悲观锁 乐观锁和悲观锁 乐观并发控制和悲观并发控制是并发控制采用的主要方法.乐观锁和悲观锁不仅在关系数据库里应用,在Hibernate.Memca

  • MySQL示例DTID主从原理解析

    目录 1.GTID基本概念 2.GTID优点 3.GTID的工作原理 4.GTID比传统复制的优势 5.启动的方法 6.GTID(一主一从)配置 6.1环境: 6.2在主库上给从库授权: 6.3确保数据一致操作 6.4配置主库 6.5配置从库 6.6配置主从复制 7.GTID(一主俩从) 8.GTID(俩主一从) 1.最新环境 2.所有服务器均关闭防火墙或者放行防火墙 3.授权连接 master01库授权普通用户 slave进行连接 master02授权普通用户 slave进行连接 4.分别进行

  • MySQL索引长度限制原理解析

    这篇文章主要介绍了MySQL索引长度限制原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 索引 TextField是不支持建立索引的 MySQL对索引字段长度有限制 innodb引擎的每个索引列长度限制为767字节(bytes),所有组成索引列的长度和不能大于3072字节 myisam引擎的每个索引列长度限制为1000字节,所有组成索引列的长度和不能大于1000字节 varchar的最大长度是指字符长度,若数据库字符集为utf-8,则一个

  • Spring事务原理解析

    目录 前言 问题描述 代码复现 排查 1. 锁失效 2. 事务隔离级别 3. 修改Spring事务传播配置 解决方案 前言 最近在编写公司APP产品的商品砍价功能,其中有一个接口涉及并发访问.自测时通过ApiFox接口管理工具进行压测,落地数据时出现了"锁失效"的情景.十分感谢后端小伙伴的帮助排查,解决了这个问题. 问题描述 并发接口中,先对主表数据进行读取,进行业务判断后,新增.修改它表的数据.在理应串行执行的情况下发生了多个请求线程读取到了相同的主表数据,导致数据处理异常.也正是前

  • MySQL数据库SELECT查询表达式解析

    数据的管理在很大一部分是在进行查找工作,而SELECT占据了很大的一部分 SELECT select_expr [,select_expr...] [ FROM table_reference WHERE [where_condition] [GROUP BY {col_name | position} [ASC| DESC],...] [HAVING where_condition] [ORDER BY {col_name | expr |position} [ASC| DESC],...]

  • Mysql数据库group by原理详解

    目录 引言 1. 使用group by的简单例子 2. group by 原理分析 2.1 explain 分析 2.2 group by 的简单执行流程 3. where 和 having的区别 3.1 group by + where 的执行流程 3.2 group by + having 的执行 3.3 同时有where.group by .having的执行顺序 3.4 where + having 区别总结 4. 使用 group by 注意的问题 4.1 group by一定要配合聚

  • MySQL数据库的索引原理与慢SQL优化的5大原则

    我们知道一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,所以查询语句的优化显然是重中之重. 本文旨在以开发工程师的角度来解释数据库索引的原理和如何优化慢查询. MySQL索引原理 1.索引目的 索引的目的在于提高查询效率,可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql.如果没有索引,那么你可能需要把所有单词看一遍才能找到你想要的,如果我

  • Spring底层事务原理解析

    目录 一.@EnableTransactionManagement工作原理 二.Spring事务基本执行原理 四.Spring事务传播机制 五.Spring事务传播机制分类 六.Spring事务强制回滚 七.TransactionSynchronization 一.@EnableTransactionManagement工作原理 开启Spring事务本质上就是增加了一个Advisor,但我们使用 @EnableTransactionManagement注解来开启Spring事务是,该注解代理的功

  • 使用Memcache缓存mysql数据库操作的原理和缓存过程浅析

    对于大型网站如facebook,ebay等网站,如果没有Memcache做为中间缓存层,数据访问不可能吃得消,对于一般网站,只要具备独立的服务器,完全可以通过配置Memcache提高网站访问速度和减少数据库压力,这里主要讨论一下Memcache和MySQL数据库交互过程的流程关系,了解Memcache的中间缓存层作用,从而深入了解Memcache机制原理. Memcache和MySQL交互流程图 如上图,传统的查询方法是直接查询数据库,数据库将结果返回给查询语句,而当有Memcache中间缓存层

随机推荐