• 事务底层原理(INNODB)

    • 前言
    • redo log

      • 为什么须要 redo log
      • 一些问题
      • 重做日志构造
      • 重做日志文件构造
      • log group与循环写入
      • 日志何时写入磁盘?
      • 数据恢复:LSN标记
      • CheckPoint 技术

        • 检查点的作用
        • 工作原理
        • 检查点何时触发?
      • 对于redo log的性能

        • redo log日志写回
        • 批改语句性能
    • undo log

      • 为什么须要undo log
      • 前置常识:理解SQL语句执行过程
      • undo log存储构造
      • undo log日志构造
      • 何时刷新回磁盘?
      • 事务提交时
      • Purge操作
      • 何时回滚?如何回滚?
    • bing log

      • 为什么须要bing log?
      • 事务二段式提交(外部)

文章已收录我的仓库:Java学习笔记与收费书籍分享

事务底层原理(INNODB)

前言

事务必须满足ACID四个个性,即原子性、一致性、隔离性和持久性,隔离性由锁来保障,咱们次要钻研事务是如何保障原子性、一致性和持久性。

redo log

为什么须要 redo log

InnoDB 存储引擎是基于磁盘存储的,并将其中的记录依照的形式进行治理,可将其视为基于磁盘的数据库系统(Disk-base Database),批改数据须要先将磁盘中的行记录读至内存,批改后再保留至内存长久化。

为了保障事务的持久性,每次执行一条SQL语句批改数据后就必须将批改后的值写入磁盘,而写入磁盘是十分迟缓的,在大型的程序下,频繁的写入磁盘会使得性能急速降落,因为这个起因,在Innodb引擎中,所有的操作都被设计在内存池中进行以提高效率,如果数据在内存池中,则间接在内存中批改,否则从磁盘读入内存中操作。

Innodb是多线程引擎,其中专门有一个后盾线程master thread周期性的将缓冲池中的内容刷新到磁盘中,这样仿佛便能够在保障持久性的同时又进步了效率,但这是不正确的,在这个周期内存在于内存池中的数据也是可能失落的,无奈保证数据的持久性,因而咱们须要引入预写日志(WAL)策略,这里的日志就是redo log,即重做日志。

WAL是很容易了解的,即提交事务时,先将批改过的内容提交到重做日志文件中进行长久化,而后再批改内存池中的页数据,期待被后盾过程刷新至磁盘,这样即时在期待的过程中内存数据因为数据库死机或其余起因而失落,也能够通过重做日志中的记录来复原该数据以保证数据的持久性。

还要留神的一点是,在未提交事务时,redo log是存在于内存缓冲区中的,这样做的目标是为了晋升效率,只有在特定条件如事务提交时,才将redo log buffer刷新到磁盘的redo log文件中。

例如,当咱们执行批改语句时,咱们先将磁盘中的行数据所在的读取至内存池虚构页中,尔后便在内存池中对该页进行批改,批改前,首先将要批改的值以及事务id的等其余信息写入redo log缓冲区,提交事务时,刷新redo log缓冲区到磁盘以长久化,之后再批改内存页中的数据,同时将该页标记为脏页master线程将内存中的脏页写回磁盘。

这样即时内存中脏页失落,数据库还是能够通过已长久化的重做日志还复原数据。

一些问题

此时,你可能会几点疑难?

  1. master线程最终也还是要将所有脏页刷新回磁盘,这相比于每批改一次数据就刷新磁盘效率高在哪呢?
  2. 重做日志可能会存在于缓存中,这样也有失落的可能。
  3. 重做日志还是要写回磁盘,会不会升高效率?
  4. 当脏页数据失落时,数据库是如何通过重做日志复原数据?

对于第一点的问题,因为每批改一次数据就写回磁盘,写回磁盘的地位可能是随机的,如果对磁盘性能略微理解的话就会晓得随机写效率是极低的,在期待肯定工夫后,此时存在大量将写回磁盘的数据,master线程可能会对这些写回进行排序,使得程序写回变得可能,齐全程序读写磁盘效率是相当于读写内存的,是十分高效的,即时是不齐全的程序,其效率也要高于随机写,这就是为什么master是周期性的写回。

对于第二点的问题,要晓得重做日志缓提交后就被刷新回磁盘,也就是说如果日志缓冲失落了,通常状况下事务处于未提交的状态,在未提交时抛出异样是正当的,当程序员发现错误产生在事务提交之前时,它就应该意识到这次事务是执行失败的,下次应该从新执行该事务。

你可能还会想:如果redo log写磁盘写一半而宕机了怎么办,此时事务已提交,但脏页未被刷新?别慌,前面咱们会讲到此时事务依然处于未实现状态,等看完了bing log内容再回过头思考一下吧。

前面两个问题咱们认真说说。

重做日志构造

重做日志构造共有51种之多,将来还会更多,这里简略阐明insert与delete的重做日志构造,对于这两种操作的重做日志构造如下图所示:

他们有着通用的头部字段:

  • type:重做日志的类型。
  • space:对于记录所在表空间的ID。
  • page_to:页偏移。

晓得了space和page_to便能够确定该记录物理页以及该记录所在,后续复原数据会利用这一点。

对于insert日志,占用内存较多,因为要存储新插入的值。

而对于delete日志,咱们仅须通过type晓得这是一条删除日志,毋庸数据字段。

重做日志文件构造

在了解重做日志自身构造后,咱们来看看重做日志是被如何组织的。

在InnoDB中,重做日志以块的模式存储,这通常是512字节,与磁盘一次性读写的大小相当,因而重做日志块的读写是一次原子操作,不须要额定的存储。

如果重做日志大小超过了512字节,那么它将被存储在两个块中,为了打消外部碎片,一个块可能和存储多个日志文件,但代价是须要更多的标记位以示意各个日志文件。

重做日志块在缓存中被组织成相似于数组的模式,咱们称这个链表位重做日志缓冲区,即redo log buffer,日志缓冲存在于内存中。

重做日志块容许同时存在多个重做日志,例如下图,有T1和T2两个日志,T1大小为762字节,在去掉头部和尾部20字节后,一个块仅能装下492字节,因而T1被宰割装入第二块中。

头部字段能够示意该块是第几块,同时也存在字段LOG_BLOCK_HDR_DATA_LEN字段标识第一个重做日志在该块中的偏移量,例如块二中该字段被设置为270,这样数据库就晓得T2的偏移量为270,而T2的尾部具备完结标记,数据库也晓得T3(如果有的话)的偏移量是370。

重做日志文件构造只须要在redo log buffer的根底上加上一些文件头信息即可,如下图所示:

这些信息的具体大小如下,Log File Header是文件头,它蕴含文件大小、版本号、LSN等一些有用信息,CP1和CP2名称为checkpoint,它蕴含检查点信息,对于检查点信息咱们前面再说。

再写入文件时,从redo log buffer头部开始顺次读取所有重做日志写入磁盘,重做日志在磁盘中被存储的模式与在缓冲区中存储模式雷同。

log group与循环写入

一个日志组由多个日志文件组成,咱们通常只应用一个日志文件组,而设置多余的日志文件组用于备份。

日志文件写回磁盘是循环写入的,什么意思呢?假如一个日志文件组有三个日志文件f1、f2和f3,咱们从f1开始,程序读取redo log buffer中的日志写入f1,当f1写满时写f2,f2写满时写f3,而f3满时则持续写f1。

<img src="https://happysnaker-1306579962.cos.ap-nanjing.myqcloud.com/img/typora/image-20210924194203896.png" alt="image-20210924194203896" style="zoom: 25%;" />

log group中的多个文件在逻辑上被组织成间断的,只管在理论的磁盘中他们不肯定要间断。

写入同一个文件内的大部分记录都是被程序组织的,因而重做日志的写入磁盘是十分快的。

日志何时写入磁盘?

这个具体的规定是:

  1. 事务被提交时。
  2. 当log buffer中内存不够时,通常应用超过一半便触发写入磁盘动作。
  3. 写入遇到CheckPoint点时。

数据恢复:LSN标记

LSN称为日志的逻辑序列号(log sequence number),在innodb存储引擎中,LSN占用8个字节。LSN的值会随着日志的写入而逐步增大。

LSN不仅存在于redo log中,还存在于理论数据页中,LSN是用于复原数据的关键点。

简略来说,LSN就是用于标记的版本号,在数据库中,随着事务产生并且条目被写入日志文件,LSN 会一直增大,在 FP3 之前,下限为 0xFFFF FFFF FFFF,LSN每次增大一个重做日志的大小。

LSN在重做日志中和理论页中都会存在,这一点是很重要的。在页中的LSN示意最初一次的被刷新LSN号。

举个简略例子而言,假如初始时LSN为0,此时咱们执行一条插入语句:insert into test value(0);,数据库会为其生成一条重做日志,设为T1,事务提交时,重做日志被长久化,同时数据库将插入数据所在的页0设置为脏页,此时页0与对应的重做日志LSN都为0。

<img src="C:\Users\happysnakers\AppData\Roaming\Typora\typora-user-images\image-20210925145317431.png" alt="image-20210925145317431" style="zoom:50%;" />

再假如上图中的脏页曾经被正确的刷新会磁盘了,那么磁盘中对应实在页的LSN即为0,咱们这里认为磁盘中的页号也是0,这是与重做日志中的页号对应的。

咱们假如T1大小为100byte,那么此时LSN号自增重做日志的大小,即$LSN = 0 + 100 = 100$,当初假如咱们执行一条批改语句,将 a 的值批改为 1,数据库从磁盘中读取数据到内存,为了不便,咱们依然认为读到虚拟内存中的页也为0,设此时为批改语句生成的重做日志为T2,那么此时的构造为:

<img src="https://happysnaker-1306579962.cos.ap-nanjing.myqcloud.com/img/typora/image-20210925150208880.png" alt="image-20210925150208880" style="zoom:50%;" />

这是正确的后果,此时页0的LSN被更新为100,那如果内存中的脏页失落了呢?数据库要如何复原信息呢?

如果此时数据库宕机而失落了此时页0的信息,那么磁盘中页0的LSN为上一次的LSN,即0,数据a的值也是0,这是齐全谬误的,当数据库启动时,它会扫描重做日志试图复原谬误。

首先扫描T1,发现T1中的日志指向物理页0,并且发现 $T1中的LSN <= 对应页中的LSN$,于是数据库就会认为该LSN版本的数据是统一的,未出错。

数据库持续读取T2,T2中的日志也指向物理页0,并且发现 $T2中的LSN > 对应页中的LSN$,数据库能够判定,该版本产生了谬误,于是数据库读取T2中的页偏移以确定对应记录的地位,依据T2中的数据批改页0中的数据,此时设置 a = 1,并更新LSN号,于是,数据库正确的从谬误中复原了,数据的持久性得以保障。

你大略曾经明确了数据恢复次要流程,数据库次要通过比拟LSN版本号以得悉是否出错,如果出错则依据重做日志中的信息以复原数据。

你能够在命令行键入mysql > SHOW ENGINE INNODB STATUS\G,找到有对于LOG的记录,其中Log Sequence Number即为以后LSN。

在咱们的形容中,一旦数据库失落数据,其必须要扫描所有的重做日志能力从谬误中恢复过来,当重做日志文件十分大时,这须要相当久的耗时,为此,引入了CheckPoint技术。

CheckPoint 技术

检查点的作用

checkpoint次要2个作用:

保障数据库的一致性,这是指将脏数据写入到硬盘,保障内存和硬盘上的数据是一样的;

缩短实例复原的工夫,实例复原要把实例异样敞开前没有写出到硬盘的脏数据通过日志进行复原。如果脏块过多,实例复原的工夫也会很长,检查点的产生能够缩小脏块的数量,从而进步实例复原的工夫。

工作原理

后面提到过,脏页回在缓冲池中持续存在一段时间后才会被后盾线程回收,如果此时咱们要敞开数据库但内存中的脏页还未被刷新怎么办,难道咱们还要期待其被刷新吗?但咱们又如何晓得内存何时被刷新呢?一旦咱们间接强制性关机,岂不是无端的让数据库陷入谬误,下一次启动时又须要大量的工夫复原?

在某些状况下,咱们须要强制性将内存中的脏页刷新回磁盘。而咱们提到过LSN号是递增的,一旦咱们被动刷新内存,并且晓得了被刷新回内存的所有脏页中最大的LSN(假如为MLSN),那么咱们就能够必定所有LSN小于MLSN的版本都曾经被失常刷新回磁盘长久化,那么下一次复原时对于这一部分咱们便不必去扫描了,这样就能够极大的节俭复原工夫。

这个最大的LSN就是检查点,顾名思义,即从这个点后开始查看,之前的点毋庸查看

在特定条件下,检查点被触发,checkpoint过程开始一个checkpoint事件,并记录下以后LSN最大的脏页,称为检查点,也叫CP RBA。

而后,checkpoint过程告诉DBWn过程将所有checkpoint RBA之前的buffer cache外面的脏块写入磁盘。

确定脏块都被写入磁盘当前,checkpoint过程将checkpoint信息(LSN)写入/更新数据文件和管制文件中。

在此咱们还要引入一个概念,称为write_pos(write_pos和checkpoint信息被保留在日志文件头部的CP1和CP2字段中),即以后写入点,那么数据库复原时只须要复原 $check$point 到 $ writepos $之间的重做日志即可。

例如以后写入LSN为13000,上一次检查点为10000,那么只需复原10000到13000之间的信息即可。

<img src="https://happysnaker-1306579962.cos.ap-nanjing.myqcloud.com/img/typora/image-20210925154437737.png" alt="image-20210925154437737" style="zoom:50%;" />

检查点何时触发?

在日志何时写入磁盘时咱们曾介绍过3种形式,事实上前两种形式其实就是触发了检查点事件,但检查点事件却不只这两点,因而我才会将第三点写上去。

当初咱们来具体的探讨一些检查点事件何时被触发。

MYSQL中的检查点分为两类,即:

  1. sharp checkpoint:强烈检查点,要求尽快将所有脏页都刷到磁盘上,对I/O资源的占有优先级高。
  2. fuzzy checkpoint(默认的形式):含糊检查点,会依据零碎负载及脏页数量适当均衡,不要求立刻将所有脏页写入磁盘,可能会刷新局部脏页。

触发机会:

  1. 数据库失常敞开时,即参数 innodb_fast_shutdown=0(默认地)时,须要执行sharp checkpoint。
  2. redo log产生切换时(即切换日志)或者redo log快满的时候进行fuzzy checkpoint。
  3. master thread每隔1秒或10秒定期进行fuzzy checkpoint。
  4. innodb保障有重做日志文件足够多的闲暇页(避免笼罩),如果发现有余,须要移除LRU链表开端的page,如果这些page是脏页,那么也须要fuzzy checkpoint。
  5. innodb buffer pool中脏页比超过限度(通常是最大大小的一半)时也会触发fuzzy checkpoint。

对于redo log的性能

redo log日志写回

即时redo log是被程序写回磁盘的,但只有是对于磁盘的IO,其性能依然会降落。学到这里,你应该发现数据库的性能与磁盘性能有很大关系。

InnoDB下存在一个参数:innodb_flush_log_at_trx_commi,可取值为: 0/1/2

innodb_flush_log_at_trx_commit=0,示意每隔一秒把log buffer刷到文件系统中(os buffer)去,并且调用文件系统的“flush”操作将缓存刷新到磁盘下来。也就是说一秒之前的日志都保留在日志缓冲区,也就是内存上,如果机器宕掉,可能失落1秒的事务数据。

innodb_flush_log_at_trx_commit=1(默认),示意在每次事务提交的时候,都把log buffer刷到文件系统中(os buffer)去,并且调用文件系统的“flush”操作将缓存刷新到磁盘下来。这样的话,数据库对IO的要求就十分高了,如果底层的硬件提供的IOPS比拟差,那么MySQL数据库的并发很快就会因为硬件IO的问题而无奈晋升。

innodb_flush_log_at_trx_commit=2,示意在每次事务提交的时候会把log buffer刷到文件系统中去,但并不会立刻刷写到磁盘。如果只是MySQL数据库挂掉了,因为文件系统没有问题,那么对应的事务数据并没有失落。只有在数据库所在的主机操作系统损坏或者忽然掉电的状况下,数据库的事务数据可能失落1秒之类的事务数据。这样的益处,缩小了事务数据失落的概率,而对底层硬件的IO要求也没有那么高(log buffer写到文件系统中,个别只是从log buffer的内存转移的文件系统的内存缓存中,对底层IO没有压力)。

但要晓得,尽管批改参数可能带来性能的晋升,但却失落了数据的一致性与持久性。

批改语句性能

后面提到过,如果要批改信息,如果信息不再内存中,必须要先读入磁盘,再磁盘中批改,最初写回磁盘,须要两次磁盘IO和一次内存操作,效率低下。

为此INNODB引入一种称为写缓存的技术,这是针对非惟一一般索引页的删除与更新语句的优化,这里我简略的介绍一下原理。

具体的,批改某个记录时(假如页不在内存中,如果在内存中不会触发写缓存),将这个批改记录在缓存中,等到下次读取该数据时,再将其合并更新,并且写入缓存。

你能够发现这样缩小了一次磁盘IO,但这也不是必然的,如果下一次读取行将到来,那么这个技术毫无意义,还会节约空间,因为批改时读入内存,当下一次读取很快到来时,数据还未被刷新,此时也会节俭一次磁盘读取。

更多信息能够自行查阅。

undo log

为什么须要undo log

redo log是为了保障事务的持久性和一致性,那么undo log便是为了保障事务的原子性,是为了事务回滚而设计的。

例如如果你执行插入语句,那么undo log中可能就会对应的记录一条删除语句,这样当该事务回滚时,就会执行undo log中的删除语句使得事务如同基本就没有被执行,即事务回滚胜利。

undo log是一种逻辑日志,因而只是将数据库逻辑地复原到原来的样子。所有批改都被逻辑地勾销了,然而数据结构和页自身在回滚之后可能大不相同。例如曾经插入的数据只是被逻辑的删除,实在数据依然存在。这与数据区自身执行SQL语句无关,数据库失常的删除语句也是一种逻辑删除,这是因为数据库要提供MVVC多版本性能,即在并发拜访下,一个事务对以后行上锁批改,另一个事务能够读取之前的版本。
undo log也是实现MVVC的底层机制。

前置常识:理解SQL语句执行过程

咱们次要阐明DELETE和UPDATE语句,SELECT和INSERT并不会有什么歧异。

向咱们之前所说的,当初大多数数据库都提供MVVC性能,即便一个事务执行了删除操作数据库也不会立刻删除,而是断定是否有其余事务在援用该记录,而后再删除,这个过程由后盾Purge线程执行。

  • delete操作不会间接删除,而是将delete对象打上delete flag,标记为删除,期待purge线程周期性的尝试回收。
  • update分为两种状况:update的列是否是主键列。

    • 如果不是主键列,update是间接进行的。
    • 如果是主键列,update分两部执行,先删除该行(也是逻辑删除),再插入一行指标行。

你可能会奇怪为什么为什么更新操作会有两种状况,情理是很简略的,非主键列间接批改是能够做到的,但主键列是在B+树上的,间接批改会使得B+树数据结构不合乎,间接批改难以操作,逻辑简单,因而采纳先删除再插入的形式。

undo log存储构造

innodb存储引擎对undo log的治理采纳段的形式,其存在于rollback segment之中,rollback segment称为回滚段,每个回滚段中有1024个undo log segment,在每个undo log segment中进行undo log页的申请,所有undo log页被组织成链表的模式。

同redo log相似,undo log页也是可被重用的,即一个页可能存在两个事务对应的undo log页。

undo log日志构造

与redo log不同,redo log是基于页信息的,而undo log是基于SQL语句的,具体的,咱们将undo log分为两种,即 insert undo log 和 update undo log。

insert undo log次要针对于insert操作,而update undo log针对于delete和update两种操作,其具体构造如下图所示:

<img src="https://happysnaker-1306579962.cos.ap-nanjing.myqcloud.com/img/typora/image-20210925172034872.png" alt="image-20210925172034872" style="zoom:50%;" />

看不懂没关系,只须要通晓undo log表白的是一种反语句,即执行插入则undo log代表删除,执行主键上更新,undo log代表删除新值与插入旧值。

每个undo log以链表的模式被组织在不同undo page中,next字段即代表下一个undo log,而undo page又以链表的模式被组织。每个undo log记录了对应的事务id、记录表空间、偏移等根底信息,咱们只需通晓事务id,从前往后遍历链表找到所属事务id的log(链表从头部插入,后插入的在前,回滚时从前往后查找即可),即可回滚事务。

何时刷新回磁盘?

如果你认真看了redo log的内容,你至多应该分明批改后的数据页会被标记为脏页,期待后盾线程回收,在这之前,该数据页会先被redo log所记录。

回到问题,undo log何时被刷新会磁盘?答案是随后台线程。undo log page被当作脏页,就像一般脏页那样被后盾线程定期刷新回磁盘。

但在这里有两个须要留神的点,一般数据页必须在事务提交时redo log被长久化后才会被批改,而undo log page在事务开始工作后,每一条批改语句都会产生undo log page,undo page源源不断地被写入而不须要等到事务提交,这样做是有起因的,只有这样,当事务未提交而产生回滚时,才有记录去尝试回滚该事务。第二个点就是undo log也须要redo log以保障其正确性。

事务提交时

事务提交后,undo log不能立刻被删除,这是因为数据库要提供MVVC多版本控制,一些事务线程会通过undo log来推断出上一个版本,InnoDB会将undo log放入删除链表(也叫历史链表)中(先提交的undo log总是在尾端),期待purge线程真正的删除它们。

例如下图删除链表,trx1示意事务1产生的undo log,它是最先提交的,因而在尾端。

Purge操作

Purge周期的清理记录以及undo log,清理记录只须要查看删除标记位即可,清理undo log要略微麻烦一点。

Purge线程必须保障一个undo log没有任何事务援用它能力删除这个日志,援用关系在undo page中对应的undo log中存在记录,因而能够通过查找undo page中的undo log查看对应是否存在援用。历史链表中并不蕴含此信息,仅仅蕴含指向undo page中对应log的指针,这样做是为了节俭内存。

如图所示,在undo page1中,其中trx5示意正在被其余事务援用:

<img src="https://happysnaker-1306579962.cos.ap-nanjing.myqcloud.com/img/typora/image-20210925192904173.png" alt="image-20210925192904173" style="zoom:50%;" />

残缺的图如下图所示:

<img src="https://happysnaker-1306579962.cos.ap-nanjing.myqcloud.com/img/typora/image-20210925193004638.png" alt="image-20210925193004638" style="zoom:50%;" />

你可能会想:从尾到头遍历删除链表,查找对应undo page中的信息,没有援用则删除。

这样做没有任何问题,但效率是十分低下的,要明确删除链表中的程序其实并不是理论事务log存储的程序,真正的undo log在事务未提交前就被写入undo page,而在提交后才被写入链表,这就导致了链表中的程序实际上并不是undo page中log寄存的数据,因为undo log可能被刷新回磁盘,如果依据链表遍历可能会产生大量随机读写,效率低效,InnoDB采纳先读链表,在程序读page的形式实现。

具体的,先读链表尾部trx1,在undo page1中查找,发现没有援用则删除trx1;尔后持续在undo page1中程序查找,下一个是trx3,删除trx3;持续程序查找,接下来是trx5,发现存在援用,则放弃查找;回到链表尾部,此时尾部为trx2,则到undo page2中程序查找......

这样做会产生大量程序读写,提高效率。

何时回滚?如何回滚?

当程序员手动调用回滚时此时会回滚;或当事务未提交而产生谬误时,此时也会回滚。

回滚时,依据事务id程序查找undo log page中的undo log lists,程序的执行undo log中的反语句以回滚信息。

你可能无奈了解当事务未提交而产生谬误时为何须要回滚,事务未提交时缓冲区中的数据页不是还未修改吗?咱们马上将解开这个谜题,事实上事务的提交并不是这么简略,而是采纳一种两阶段的体检形式,这波及到另一种日志:bing log。

bing log

为什么须要bing log?

binlog是一个二进制格局的文件,用于记录用户对数据库更新的SQL语句信息,更改数据库表和更改内容的SQL语句都会记录到binlog里。

bing log是一种逻辑日志,记录着SQL操作。例如执行插入语句,bing log可能会记录某某工夫,插入一条 XXX 记录;bing log不会记录查问操作,事实上undo和redo也不会记录。

那么bing log有什么用呢?不是有了 redo log 和 undo log吗?

undo log记录的是反语句,次要为了实现回滚操作,事务提交后undo log就可能会被删除。redo log的作用是为了保障内存中的数据的持久性,当内存中的脏页被刷新,redo log也就生效,会被笼罩写。redo 和 undo 都有一个问题,即它们都是短暂存在的。

而bing log记录着所有执行操作,并持久性的存在于磁盘中。bing log次要用于查看数据库的历史变更记录、增量备份(能够比拟绝对于上一次备份减少那些内容,仅备份这些减少的内容)、工夫回溯(复原到指定工夫点的状态)或数据库复制。

bing log在站在MYSQL服务层上的,其负责整个MYSQL平安备份与复原,针对于所有的引擎。而redo和undo仅仅常识InnoDB提供的、针对于事务的日志,是齐全不同的概念。

事务二段式提交(外部)

MYSQL默认开启bing log,也倡议开启bing log,当开启bing log后,在INNODB引擎下就会存在一些问题,即bing log和redo log不统一的问题

举个简略的例子,在原来的状态中,事务提交后redo log被刷新回磁盘,此时bing log还未写入磁盘,数据库忽然宕机,复原时,因为redo log写入,数据不会有任何问题,但原来的bing log还未被写入!此时数据库状态与bing log不统一,咱们违反了数据库的一致性!

必须在bing log也被正确写回后才算事务提交胜利。bing log写回失败必须要做某些解决!

二段式提交就是为了解决redo log和bing log写回不统一的问题。

在二段式提交中,分为两个阶段:

  1. prepare过程
  2. commit过程

当事务提交时,会立刻陷入第一个阶段,即prepare阶段。

prepare过程:

  • 设置该事务对应undo state=TRX_UNDO_PREPARED,示意正式进入prepare过程。
  • 将redo日志刷新回磁盘,批改内存数据页。

而后会陷入第二阶段。

commit过程:

  • 将事务产生的binlog写回磁盘,当这个动作被实现时,事务被确认已提交,即时前面的动作未实现。
  • 将undo写入删除链表中,期待purge删除。

思考问题,当redo log写回磁盘失败时,此时数据仍未变脏,事务ACID个性未被毁坏,该事务执行失败,回到最后的样子;当bing log写回磁盘失败时,数据页已变脏,必须借助undo log回滚事务,当undo log失落时,依据redo log重建undo log。

这样,咱们便解决了一系列的问题,事务的ACD个性(本文章未设计隔离性)失去保障。

全文完。