MySQL执行流程

1. 一条SQL语句是怎么执行的?

在这里插入图片描述

1.1 连接

首先,数据是存储在MySQL服务端的,应用程序或者工具都是客户端,客户端想要读写数据,第一步得跟服务端建立连接。

1.2 查询缓存

MySQL内部自带了一个缓存模块,但是MySQL的缓存默认是关闭的,因为MySQL自带的缓存的应用场景有限,第一个是它要求SQL语句必须一模一样,例如中间多一个空格、字母大小写不同都被认为是不一样的SQL语句。
第二个是表里面的任何一条数据发生变化的时候,这张表所有的缓存都会失效,所以对于大量数据更新的应用,也不适合。
缓存这一块还是交给ORM框架,或者独立的缓存服务,比如Redis来处理更合适。
在MySQL8.0中,查询缓存已经被移除了。
可以使用这行语句来查看MySQL查询缓存的相关属性

show variables like 'query_cache%'; 

1.3 语法解析和预处理

假如随便执行一个字符串,服务器报了一个1064的错:
[Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the rightsyntaxtousenear’penyuyan’atline1 它是怎么知道输入的内容是错误的?
这个就是MySQL的Parser解析器和Preprocessor预处理模块。
这一步主要做的事情是对SQL语句进行词法和语法分析和语义的解析

1.3.1.词法解析

词法分析就是把一个完整的SQL语句打碎成一个个的单词。
比如一个简单的SQL语句:

select name from user where id=1

它会打碎成8个符号,每个符号是什么类型,从哪里开始到哪里结束。

1.3.2.语法解析

第二步就是语法分析,语法分析会对SQL做一些语法检查,比如单引号有没有闭合,
然后根据MySQL定义的语法规则,根据SQL语句生成一个数据结构。
这个数据结构我们把它叫做解析树(select_lex)。
在这里插入图片描述
词法语法分析是一个非常基础的功能,编译器、搜索引擎如果要识别语句,必须也要有词法语法分析功能。

1.3.3 预处理器

如果写了一个词法和语法都正确的SQL,但是表名或者字段不存在,会在哪里报错?
是解析的时候报错还是执行的时候报错?
实际上还是在解析的时候报错,解析SQL的环节里面有个预处理器。
它会检查生成的解析树,解决解析器无法解析的语义。比如,它会检查表和列名是否存在,检查名字和别名,保证没有歧义。
预处理之后得到一个新的解析树。

1.4. 查询优化(Query Optimizer)与查询执行计划

1.4.1 什么是优化器?

解析树是一个可以被执行器认识的数据结构。
一条SQL语句是不是只有一种执行方式?或者说数据库最终执行的SQL是不是就是发送的SQL?
这个答案是否定的。一条SQL语句是可以有很多种执行方式的,最终返回相同的结果,他们是等价的。但是如果有这么多种执行方式,这些执行方式怎么得到的?最终选择哪一种去执行?根据什么判断标准去选择?
这个就是MySQL的查询优化器的模块(Optimizer)。
查询优化器的目的就是根据解析树生成不同的执行计划(ExecutionPlan),然后选择一种最优的执行计划,MySQL里面使用的是基于开销(cost)的优化器,那种执行计划开销最小,就用哪种。
可以使用这个命令查看查询的开销:

show status like 'Last_query_cost';

1.4.2 优化器可以做什么?
MySQL的优化器能处理哪些优化类型呢?
举两个简单的例子:
1、当我们对多张表进行关联查询的时候,以哪个表的数据作为基准表(先访问哪张表)。
2、有多个索引可以使用的时候,选择哪个索引。
3、对于查询条件的优化,比如移除1=1 之类的恒等式,移除不必要的括号,表达式的计算,子查 询和连接查询的优化。

1.4.3. 优化器得到的结果

优化器最终会把解析树变成一个执行计划(execution_plans),执行计划也是一个数据结构。
当然,这个执行计划是不是一定是最优的执行计划呢?不一定,因为MySQL也有可能覆盖不到所有的执行计划。
我们怎么查看MySQL的执行计划呢?比如多张表关联查询,先查询哪张表?在执行查询的时候可能用到哪些索引,实际上用到了什么索引?
MySQL提供了一个执行计划的工具。我们在SQL语句前面加上EXPLAIN,就可以看到执行计划的信息。

EXPLAIN select cust_name from customer where cust_id=14;

如果要得到详细的信息,还可以用FORMAT=JSON。

1.5 存储引擎

1.5.1 存储引擎基本介绍

表在存储数据的同时,还要组织数据的存储结构,这个存储结构就是由我们的存储引擎决定的,所以我们也可以把存储引擎叫做表类型。
在MySQL里面,支持多种存储引擎,他们是可以替换的,所以叫做插件式的存储引擎。

1.5.2 查看存储引擎

查看数据库里面已经存在的表的存储引擎:

show table status from `ssm_crm`;

在MySQL里面,我们创建的每一张表都可以指定它的存储引擎,而不是一个数据库只能使用一个存储引擎。存储引擎的使用是以表为单位的(所以叫表类型)。而且,创建表之后还可以修改存储引擎。
默认情况下,每个数据库都有一个自己的文件夹,存储在服务器端,可以通过下面这条语句查看

show variables like 'datadir';

任何一个存储引擎都有一个frm文件,这个是表结构定义文件。
不同的存储引擎存放数据的方式不一样,产生的文件也不一样,innodb 是 1 个,
memory没有,myisam是两个。

1.5.3 存储引擎比较

我们可以用这个命令查看MySQL对存储引擎的支持情况:

show engines;

其中有存储引擎的描述和对事务、XA协议和savepoints的支持。
XA协议用来实现分布式事务(分为本地资源管理器,事务管理器)。
Savepoints用来实现子事务(嵌套事务)。创建了一个Savepoints之后,事务就可以回滚到这个点,不会影响到创建Savepoints之前的操作。
在这里插入图片描述
MyISAM(3个文件)

MySQL自带的存储引擎,由ISAM升级而来。
应用范围比较小。表级锁定限制了读/写的性能,因此在Web 和数据仓库配置中,它通常用于只读或以读为主的工作。
特点:
支持表级别的锁(插入和更新会锁表)。不支持事务。
拥有较高的插入(insert)和查询(select)速度。
存储了表的行数(count速度更快)。
(怎么快速向数据库插入100万条数据?我们有一种先用MyISAM插入数据,然后
修改存储引擎为InnoDB的操作。)
适合:只读之类的数据分析的项目。

InnoDB(2个文件)

mysql5.7中的默认存储引擎。 InnoDB是一个事务安全(与ACID兼容)的MySQL存储引擎,它具有提交、回滚和崩溃恢复功能来保护用户数据。InnoDB行级锁(不升级为更粗粒度的锁)和Oracle风格的一致非锁读提高了多用户并发性和性能。InnoDB将用户数据存储在聚集索引中,以减少基于主键的常见查询的I/O。为了保持数据完整性,InnoDB还支持外键引用完整性约束。

特点:

  • 支持事务,支持外键,因此数据的完整性、一致性更高。
  • 支持行级别的锁和表级别的锁。
  • 支持读写并发,写不阻塞读(MVCC)。
  • 特殊的索引存放方式,可以减少IO,提升查询效率。
  • 适合:经常更新的表,存在并发读写或者有事务处理的业务系统。

Memory(1 个文件)

将所有数据存储在RAM中,以便在需要快速查找非关键数据的环境中快速访问。这个引擎以前被称为堆引擎。其使用案例正在减少; InnoDB及其缓冲池内存区域提供了一种通用、持久的方法来将大部分或所有数据保存在内存中,而ndbcluster为大型分布式数据集提供了快速的键值查找。

特点:

  • 把数据放在内存里面,读写的速度很快,但是数据库重启或者崩溃,数据会全部消失。只适合做临时表。
  • 将表中的数据存储到内存中。
  • 默认使用哈希索引。

CSV(3个文件)

它的表实际上是带有逗号分隔值的文本文件。 csv表允许以csv格式导入或转储数据,以便与读写相同格式的脚本和应用程序交换数据。因为csv 表没有索引,所以通常在正常操作期间将数据保存在innodb表中,并且只在导入或导出阶段使用csv表。
特点:不允许空行,不支持索引。格式通用,可以直接编辑,适合在不同数据库之
间导入导出。

不同的存储引擎提供的特性都不一样,它们有不同的存储机制、索引方式、锁定水平等功能。
我们在不同的业务场景中对数据操作的要求不同,就可以选择不同的存储引擎来满足我们的需求,这个就是MySQL支持这么多存储引擎的原因。

1.5.4 如何选择存储引擎

  • 如果对数据一致性要求比较高,需要事务支持,可以选择InnoDB。
  • 如果数据查询多更新少,对查询性能要求比较高,可以选择MyISAM。
  • 如果需要一个用于查询的临时表,可以选择Memory。
  • 如果所有的存储引擎都不能满足你的需求,并且技术能力足够,可以根据官网内部手册用C语言开发一个存储引擎,按照这个开发规范,实现相应的接口,给执行器操作。也就是说,为什么能支持这么多存储引擎,还能自定义存储引擎,表的存储引擎改了对Server访问没有任何影响,就是因为大家都遵循了一定了规范,提供了相同的操作接口。

1.6. 执行引擎(Execution Engine),返回结果

执行器,或者叫执行引擎,它利用存储引擎提供的相应的API来完成操作。最后把数据返回给客户端,即使没有结果也要返回。

总结:一条SQL语句的执行流程大致为,客户端先与MySQL服务器建立连接,然后,发送一条查询语句,如果MySQL开启了缓存的话,会将SQL语句存到缓存中,然后,解析器进行词法和语法的解析,接着预处理器会进行再次检查,比如检查表名和列名是否存在,没有问题的话,优化器会对SQL语句进行优化,生成一个执行计划,交给执行器执行SQL,执行器调用存储引擎,存储引擎读取磁盘数据,将查询结果交给执行器,执行器再将查询结果反馈给客户端或缓存。

2. 架构分层

总体上,我们可以把 MySQL 分成两层,执行操作的服务层,和存储管理数据的存储引擎层(参考 MyBatis:接口、核心、基础)
在这里插入图片描述

2.1 服务层

包括客户端跟服务端的连接,查询缓存的判断、对 SQL 语句进行词法和语法的解析(比如关键字怎么识别,别名怎么识别,语法有没有错误等等)。然后就是优化器,MySQL 底层会根据一定的规则对我们的 SQL 语句进行优化,最后交给执行器去执行。

2.2 存储引擎层

存储引擎就是我们的数据真正存放的地方,在 MySQL 里面支持不同的存储引擎。再往下就是文件管理系统,内存或者磁盘。

3. 一条更新 SQL 是如何执行的?

更新流程和查询流程有什么不同呢?基本流程也是一致的,也就是说,它也要经过解析器、优化器的处理,最后交给执行器。 区别就在于拿到符合条件的数据之后的操作。

3.1 缓冲池 Buffer Pool

InnoDB作为MySQL的存储引擎,数据是存放在磁盘中的,但如果每次读写数据都需要磁盘IO,效率会很低。为此,InnoDB提供了缓存(Buffer Pool),作为访问数据库的缓冲:当从数据库读取数据时,会首先从Buffer Pool中读取,如果Buffer Pool中没有,则从磁盘读取后放入Buffer Pool;当向数据库写入数据时,会首先写入Buffer Pool,Buffer Pool中修改的数据会定期刷新到磁盘中 。在这里插入图片描述

修改数据的时候,先修改内存缓冲池里面的页。内存的数据页和磁盘数据不一致的时候,我们把它叫做脏页。那脏页什么时候同步到磁盘呢?
InnoDB 里面有专门的后台线程把 Buffer Pool 的数据写入到磁盘,每隔一段时间就一次性地把多个修改写入磁盘,这个动作就叫做刷脏

3.2 InnoDB 内存结构和磁盘结构

官方文档
在这里插入图片描述

内存结构里面主要是 Buffer Pool、Change Buffer、Log Buffer、AHI,下面分别讲一下。

Buffer Pool

官方文档

Buffer Pool 缓存的是 page 页面信息。
查看服务器状态,里面有很多跟 Buffer Pool 相关的信息,这些状态都可以在官网查到详细的含义。

SHOW STATUS LIKE '%innodb_buffer_pool%';

在这里插入图片描述
Buffer Pool 默认大小是 128M(134217728 字节),可以调整。
查看参数(系统变量):

SHOW VARIABLES like '%innodb_buffer_pool%';

(redo)Log Buffer

Buffer Pool的使用大大提高了读写数据的效率,但是也带了新的问题:如果MySQL宕机,而此时Buffer Pool中修改的数据还没有刷新到磁盘,就会导致数据的丢失,事务的持久性无法保证。为了避免这个问题,InnoDB 把所有对页面的修改操作专门写入一个日志文件Redo Log。如果有未同步到磁盘的数据,数据库在启动的时候,会从这个日志文件进行恢复操作(实现 crash-safe)。我们说的事务的 ACID 里面 D(持久性),就是用它来实现的。
在这里插入图片描述

这个日志文件就是磁盘的 redo log(叫做重做日志),对应于/var/lib/mysql/目录下的 ib_logfile0 和 ib_logfile1,默认 2 个文件,每个 48M,可以使用如下命令查看

show variables like 'innodb_log%';
参数含义
innodb_log_file_size指定每个文件的大小,默认 48M
innodb_log_files_in_group指定文件的数量,默认为 2
innodb_log_group_home_dir指定文件所在路径,相对或绝对。如果不指定,则为datadir 路径。

3.3 redo log如何保证事务的持久性?

Redo log可以简单分为以下两个部分:

  • 一是内存中重做日志缓冲 (redo log buffer),是易失的,在内存中
  • 二是重做日志文件 (redo log file),是持久的,保存在磁盘中

这里再细说下写入Redo Log的时机:

  • 在数据页修改完成之后,在脏页刷出磁盘之前,写入redo日志。注意的是先修改数据,后写日志
  • redo日志比数据页先写回磁盘
  • 聚集索引、二级索引、undo页面的修改,均需要记录Redo日志。

在这里插入图片描述
在 MySQL中,如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。为了解决这个问题,MySQL 的设计者就采用了日志(redo log)来提升更新效率。

当事务提交时,先将 redo log buffer 写入到 redo log file 进行持久化,待事务的commit操作完成时才算完成。这种做法也被称为 Write-Ahead Log(预先日志持久化),在将数据写入磁盘前,先将内存中相应的日志页持久化。

具体来说,当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log(redo log buffer)里面,并更新内存(buffer pool),这个时候更新就算完成了。同时,InnoDB 引擎会在适当的时候(如系统空闲时),将这个操作记录更新到磁盘里面(刷脏页)。

3.4 同样是写磁盘,为什么不直接写到 db file 里面去?为什么先写日志再写磁盘?

如果我们所需要的数据是随机分散在磁盘上不同页的不同扇区中,那么找到相应的数据需要等到磁臂旋转到指定的页,然后盘片寻找到对应的扇区,才能找到我们所需要的一块数据,一次进行此过程直到找完所有数据,这个就是随机 IO,读取数据速度较慢。

假设我们已经找到了第一块数据,并且其他所需的数据就在这一块数据后边,那么就不需要重新寻址,可以依次拿到我们所需的数据,这个就叫顺序 IO。

刷盘是随机 I/O,而记录日志是顺序 I/O(连续写的),顺序 I/O 效率更高。因此先把修改写入日志文件,在保证了内存数据的安全性的情况下,可以延迟刷盘时机,进而提升系统吞吐。

3.5 数据写入后的最终落盘,是从 redo log 更新过来的还是从 buffer pool 更新过来的呢?

实际上,redo log 并没有记录数据页的完整数据,所以它并没有能力自己去更新磁盘数据页,也就不存在由 redo log 更新过去数据最终落盘的情况。

① 数据页被修改以后,跟磁盘的数据页不一致,称为脏页。最终数据落盘,就是把内存中的数据页写盘。这个过程与 redo log 毫无关系。

② 在崩溃恢复场景中,InnoDB 如果判断到一个数据页可能在崩溃恢复的时候丢失了更新,就会将它读到内存,然后让 redo log 更新内存内容。更新完成后,内存页变成脏页,就回到了第一种情况的状态。

3.6 redo log buffer 是什么?是先修改内存,还是先写 redo log 文件?

在一个事务的更新过程中,日志是要写多次的。比如下面这个事务:

begin;
INSERT INTO T1 VALUES ('1', '1');
INSERT INTO T2 VALUES ('1', '1');
commit;

这个事务要往两个表中插入记录,插入数据的过程中,生成的日志都得先保存起来,但又不能在还没 commit 的时候就直接写到 redo log 文件里。

因此就需要 redo log buffer 出场了,它就是一块内存,用来先存 redo 日志的。也就是说,在执行第一个 insert 的时候,数据的内存被修改了,redo log buffer 也写入了日志。

但是,真正把日志写到 redo log 文件,是在执行 commit 语句的时候做的。

redo log buffer 本质上只是一个 byte 数组,但是为了维护这个 buffer 还需要设置很多其他的 meta data,这些 meta data 全部封装在 log_t 结构体中。

3.7 redo log顺序写入磁盘?

redo log以顺序的方式写入文件,当全部文件写满的时候则回到第一个文件相应的起始位置进行覆盖写,每次提交事务之后,都先将相关的操作日志写入redo日志文件中,并且都追加到文件末尾,这是一个顺序I/O。
在这里插入图片描述
图中展示了一组 4 个文件的 redo log 日志,checkpoint 是当前要擦除的位置,擦除记录前需要先把对应的数据落盘(更新内存页,等待刷脏页)。write pos 到 checkpoint 之间的部分可以用来记录新的操作,如果 write pos 和 checkpoint 相遇,说明 redolog 已满,这个时候数据库停止进行数据库更新语句的执行,转而进行 redo log 日志同步到磁盘中。checkpoint 到 write pos 之间的部分等待落盘(先更新内存页,然后等待刷脏页)。

有了 redo log 日志,那么在数据库进行异常重启的时候,可以根据 redo log 日志进行恢复,也就达到了 crash-safe。

redo log 用于保证 crash-safe 能力。innodb_flush_log_at_trx_commit 这个参数设置成 1 的时候,表示每次事务的 redo log 都直接持久化到磁盘。这个参数建议设置成 1,这样可以保证 MySQL 异常重启之后数据不丢失。

3.8 redo log 有什么特点?

  1. redo log 是 InnoDB 存储引擎实现的,并不是所有存储引擎都有。支持崩溃恢复是 InnoDB 的一个特性。
  2. redo log 是物理日志,记录的是“在某个数据页上做了什么修改”。
  3. redo log 的大小是固定的,前面的内容会被覆盖,一旦写满,就会触发 buffer pool到磁盘的同步,以便腾出空间记录后面的修改。
  4. redo log 的内容主要是用于崩溃恢复。磁盘的数据文件,数据来自 buffer pool(只有 redo log 写满了,不能再记录更多内存的数据了,才把 buffer pool 刷盘,然后覆盖redo log)。

3.9 undo Log

undo Log(撤销日志或者回滚日志) 记录了事务发生之前的数据状态(不包括 select)。如果修改数据时出现异常,可以用 undo log 来实现回滚操作**(实现原子性)**。在执行 undo 的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,属于逻辑格式的日志。

实现原子性的关键,是当事务回滚时能够撤销所有已经成功执行的sql语句。 InnoDB 实现回滚,靠的是undo log :当事务对数据库进行修改时,InnoDB 会生成对应的undo log ,如果事务执行失败或调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子。

3.10 bin Log

前面讲的两个日志是存储引擎(InnoDB)层的日志,而 Server 层也有自己的日志,称为 bin Log(归档日志)。

binlog 以事件的形式记录了所有的 DDL 和 DML 语句,比如“给 ID=1 这一行的count 字段加 1 ”,因为它记录的是操作而不是数据值,属于逻辑日志)。binlog 可以用来做主从复制和崩溃恢复。
跟 redo log 不一样,它的文件内容是可以追加的,没有固定大小限制。
在开启了 binlog 功能的情况下,我们可以把 binlog 导出成 SQL 语句,把所有的操作重放一遍,来实现数据的(归档)恢复。
binlog 的另一个功能就是用来实现主从复制,它的原理就是从服务器读取主服务器的 binlog,然后执行一遍

为什么会有两份日志呢?

因为最开始 MySQL 里并没有 InnoDB 引擎。MySQL 自带的引擎是 MyISAM,但是 MyISAM 没有 crash-safe 的能力,binlog 日志只能用于归档。而 InnoDB 是另一个公司以插件形式引入 MySQL 的,既然只依靠 binlog 是没有 crash-safe 能力的,所以 InnoDB 使用另外一套日志系统——也就是 redo log 来实现 crash-safe 能力。

redo Log 和 bin Log的不同点

  1. redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
  2. redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。
  3. redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

3.11 更新语句流程

在这里插入图片描述

有了对这两个日志的概念性理解后,再来看执行器和 InnoDB 引擎在执行这个 update 语句时的内部流程。

① 执行器先找引擎取 ID=1 这一行。ID 是主键,引擎直接用树搜索找到这一行。如果 ID=1 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。

② 执行器拿到引擎给的行数据,修改行数据,得到新的一行数据,再调用引擎接口写入这行新数据。

③ 引擎将这行新数据更新到内存(InnoDB Buffer Pool)中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。

④ 执行器生成这个操作的 binlog,并把 binlog 写入磁盘。

⑤ 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成。

其中将 redo log 的写入拆成了两个步骤:prepare 和 commit,这就是两阶段提交(2PC)。

3.12 为什么必须有“两阶段提交”呢?

如果不使用两阶段提交,假设当前 ID=2 的行,字段 c 的值是 0,再假设执行 update 语句过程中在写完第一个日志后,第二个日志还没有写完期间发生了 crash,会出现什么情况呢?

先写 redo log 后写 binlog。 假设在 redo log 写完,binlog 还没有写完的时候,MySQL 进程异常重启。由于我们前面说过的,redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 c 的值是 1。
但是由于 binlog 没写完就 crash 了,这时候 binlog 里面就没有记录这个语句。因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。
然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0,与原库的值不同。

先写 binlog 后写 redo log。 如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效,所以这一行 c 的值是 0。但是 binlog 里面已经记录了“把 c 从 0 改成 1”这个日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这一行 c 的值就是 1,与原库的值不同。

可以看到,如果不使用“两阶段提交”,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致

简单说,redo log 和 binlog 都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。

3.13 两阶段提交原理

两阶段提交原理描述:

① redo log 写盘,InnoDB 事务进入 prepare 状态。

② 如果前面 prepare 成功,binlog 写盘,那么再继续将事务日志持久化到 binlog,如果持久化成功,那么 InnoDB 事务则进入 commit 状态

redo log 和 binlog 有一个共同的数据字段,叫 XID。崩溃恢复的时候,会按顺序扫描 redo log:

① 如果碰到既有 prepare、又有 commit 的 redo log,就直接提交;

② 如果碰到只有 parepare、而没有 commit 的 redo log,就拿着 XID 去 binlog 找对应的事务。binlog无记录(不完整),回滚事务,binlog有记录(完整),提交事务。

推荐阅读 count(*)实现原理+两阶段提交总结

如有不对或不足之处,欢迎指正,谢谢!

  • 16
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值