日志是 mysql 数据库的重要组成部分,记录着数据库运行期间各种状态信息。mysql日志主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。尤为重要的是二进制日志( binlog )和事务日志(包括redo log 和 undo log )。
MySQL在事务实现机制上采用的是WAL(Write-ahead logging,预写式日志)机制实现,将所有的修改都先被写入到日志中,然后在被应用到系统中,有redo和undo两部分信息。
redo log被称为重做日志,每当有操作时,在数据变更之前将操作写入redo log,这样发生掉电之类的情况时系统可以再重启后继续操作。
undo log被称为撤销日志,当一些变更执行到一半无法完成时,可根据撤销日志恢复到变更之间的状态。
MySQL中用redo log在系统崩溃重启时修复数据,保证事务的持久性;而undo log来保证事务的原子性。
1、redo日志
1.1、为什么需要redo日志
MySQL只要事务提交成功,对数据库做的修改就会被永久保存下来,不会因为任何原因再回到原来的状态。
如果在每次事务提交的时候,将该事务涉及修改的数据页全部刷新到磁盘中,会有两方面严重的性能问题:因Innodb是以 页 为单位进行磁盘交互的,而一个事物很可能只修改了 一个数据页里面的几个字节,此时若将完整的数据页刷到磁盘,浪费资源;若一个事务涉及修改多个数据页,并且这些数据页在物理上并不连续,使用随机IO写入性能太差。为此MySQL引入了redo log,即只记录事务对数据也做了哪些修改,可以完美的解决性能问题。
1.2、redo日志存储位置
MySQL使用如下命令查看数据目录:
SHOW VARIABLES LIKE 'datadir'
在数据目录下下默认有两个名为ib_logfile0和ib_logfile1的文件,即为redo日志。
1.3、redo日志配置参数
redo log文件可以通过如下下边几个启动参数来调节:
innodb_log_group_home_dir,该参数指定了redo日志文件所在的目录,默认值就是当前的数据目录。
innodb_log_file_size,该参数指定了每个redo日志文件的大小,默认值为48MB。
innodb_log_files_in_group,该参数指定redo日志文件的个数,默认值为2,最大值为100。
磁盘上redo日志文件是以一个日志文件组的形式出现的,文件以 ib_logfile[数字](数字可以是0、1、2...)的形式进行命名。
在将redo日志写入日志文件组时,是从ib_logfile0开始写,若ib_logfile0写满了,接着ib_logfile1写,依次类推....,若写的最后一个文件也满了,重新转到ib_logfile0继续写(覆盖写)。即 redo 实现上采用大小固定、循环写入的而方式,当写到结尾时,会回到开头循环写日志。
1.4、redo日志内容
redo log 包括两部分:一个是内存中的日志缓冲( redo log buffer ),另一个是磁盘上的日志文件( redo logfile)。mysql 每执行一条 DML 语句,先将记录写入 redo log buffer,后续某个时间点再一次性将多个操作记录写到 redo log file。这种 先写日志,再写磁盘 的技术就是 MySQL里经常说到的 WAL(Write-Ahead Logging) 技术。
在OS(计算机操作系统)中,用户空间( user space )下的缓冲区数据一般情况下是无法直接写入磁盘的,中间必须经过操作系统内核空间( kernel space )缓冲区( OS Buffer )。因此, redo log buffer 写入 redo logfile 实际上是先写入 OS Buffer ,然后再通过系统调用 fsync() 将其刷到 redo log file中。
在innodb中,既有redo log 需要刷盘,还有 数据页 也需要刷盘, redo log存在的意义主要就是降低对 数据页 刷盘的要求 。
启动 innodb 时,总是会进行恢复操作。因为 redo 日志记录的是数据页的物理变化,因此恢复的时候速度比逻辑日志(如 binlog )要快很多。
重启innodb 时,首先会检查磁盘中数据页的 LSN ,如果数据页的LSN 小于日志中的 LSN ,则会从 checkpoint 开始恢复。
1.5、redo日志的作用
在访问MySQL数据之前,需要把在磁盘上的页缓存到内存中的Buffer Pool后才可以访问。若只在内存的Buffer Pool中修改了页面。假设在事务提交后突然MySQL服务器突然宕机,导致内存中的数据都失效了,则已提交的事务对数据库做的更改也丢失了,如何保证更新的数据的持久性呢?
简单的处理是把该事务所修改的所有页面都刷新到磁盘,会出现如下问题:
·浪费资源:在InnoDB中是以页为单位来进行磁盘IO的,默认一个页面16KB,若仅修改某页面中的一个字节,在该事务提交时将一个完整的页面从内存中刷新到磁盘,太浪费资源。
·随机IO刷盘比较慢:一个事务可能包含很多语句,即使是一条语句也可能修改许多页面,该事务修改的这些页面可能并不相邻,这就意味着在将某个事务修改的Buffer Pool中的页面刷新到磁盘时,需要进行很多的随机IO,随机IO比顺序IO要慢。
MySQL让已经提交的事务对数据库中数据所做的修改永久生效,即便系统崩溃,在重启后也可将修改恢复出来,无需在每次事务提交时将该事务在内存中修改过的全部页面刷新到磁盘,只需把修改了哪些内容记录一下,记录的文件称为重做日志,即redo log,也可称为redo日志。
在与事务执行过程中产生的redo日志刷新到磁盘的好处如下:
·redo日志占用的空间小,存储表空间ID、页号、偏移量以及需要更新的值所需的存储空间很小;
·redo日志是顺序写入磁盘,在执行事务的过程中,每执行一条语句,就可能产生若干条redo日志,这些日志是按照产生的顺序写入磁盘的,及顺序IO。
1.6、redo日志的格式
redo日志本质上记录了事务对数据库做了哪些修改,大部分类型的redo日志有以下通用的结构:
各个部分的详细释义如下:
type:该条redo日志的类型,redo日志设计大约有53种不同的类型日志。
space ID:表空间ID。
page number:页号。
data:该条redo日志的具体内容。
1.6.1.简单的redo日志类型
若某张表没有主键,并且没有定义不允许存储NULL值的UNIQUE键,则InnoDB会自动为表添加一个名为row_id的隐藏列作为主键。
row_id隐藏列进行赋值的方式如下:
· 内存中维护一个全局变量,当向某个包含row_id隐藏列的表中插入一条记录时,就会把这个全局变量的值当做新记录的row_id的值,并且把这个全局变量+1; · 每当这个全局变量的值为256的倍数时,就会将该变量的值刷新到系统表空间页号为7的页面中一个名为Max Row Id的属性中。此时需要把这次对这个页面的修改以redo日志的形式记录下来; · 当系统启动时,会将这个Max Row Id属性加载到内存中。
InnoDB把这种redo日志称之为物理日志,并且根据在页面中写入数据的多少划分了几种不同的redo日志类型:
MLOG_1BYTE | type=1 | 在页面的某个偏移量处写入1字节的redo日志类型 |
MLOG_2BYTE | type=2 | 在页面的某个偏移量处写入2字节的redo日志类型 |
MLOG_4BYTE | type=4 | 在页面的某个偏移量处写入4字节的redo日志类型 |
MLOG_8BYTE | type=8 | 在页面的某个偏移量处写入8字节的redo日志类型 |
Max Row ID属性实际占用8个字节的存储空间,所以在修改页面中的该属性时,会记录一条类型为MLOG_8BYTE的redo日志,MLOG_8BYTE的redo日志结构如下所示:
offset代表在页面中的偏移量。
1.6.2.复杂的redo日志类型
执行一条语句会修改非常多的页面,包括系统数据页面和用户数据(用户数据:聚簇索引和二级索引对应的B+树)页面。
以一条 INSERT 语句为例,除了要向B+树的页面中插入数据,也可能更新系统数据 Max Row ID 的值,但对用户而言,更关心的是语句对B+树做更新。
表中包含多少个索引,一条INSERT语句就可能更新多少棵B+树。
针对某一B+树而言,既可能更新叶子节点页面,也可能更新非叶子节点页面,也可能创建新的页面(在该记录插入的叶子节点的剩余空间较少,不足以存放该记录时,会进行页面的分裂,在非叶子节点页面中添加目录项记录)。
复杂的redo日志的示意图如下:
redo日志会把事务在执行过程中对数据库所做的所有修改都记录下来,在之后系统崩溃重启后可以把事务所做的任何修改都恢复出来。
1.7、redo日志的写入过程
1.7.1、redo log block和日志缓冲区
InnoDB为了更好的进行系统崩溃恢复,将生成的redo日志都放在了大小为512字节的块中。
在写入redo日志时不能直接写到磁盘上,实际上在服务器启动时就向操作系统申请了一大片称为redo log buffer的连续内存,即redo日志缓冲区,简称为 log buffer。该内存空间被划分成若干个连续的redo log block,可通过启动参数 innodb_log_buffer_size 指定log buffer的大小,该启动参数的默认值为16MB。
1.7.2、redo日志刷盘时机
2.1、事务提交
事务提交时,为保证持久性,必须把修改的页面对应的redo日志刷新到磁盘。可以通过 innodb_flush_log_at_trx_commit 参数控制。
该变量有3个可选的值:
码值 | 含义 | 优缺点 |
0 | 在事务提交时不立即向磁盘中同步redo日志,该任务是交给后台线程做的 | 会加快请求处理速度,但是如果事务提交后服务器挂了,后台线程没有及时将redo日志刷新到磁盘,那么该事务对页面的修改会丢失。 |
1 | 在事务提交时需要将redo日志同步到磁盘,可以保证事务的持久性 | innodb_flush_log_at_trx_commit的默认值是1 |
2 | 在事务提交时需要将redo日志写到操作系统的缓冲区中,但并不需要保证将日志真正的刷新到磁盘 | 如果数据库挂了,操作系统没挂的话,事务的持久性还是可以保证的,但是操作系统也挂了的话,那就不能保证持久性了 |
2.2、写入log buffer的redo日志量已经占满了log buffer总容量的大约一半左右
若当前写入log buffer的redo日志量已占满了log buffer总容量的一半左右,需要把这些日志刷新到磁盘上。
2.3、后台有一个线程,大约每秒都会刷新一次log buffer中的redo日志到磁盘
2.4、正常关闭服务器
1.7.3.崩溃后的恢复
3.1、恢复机制
在服务器不宕机的情况下,redo日志不仅没用,反而让性能变差,但万一数据库挂了,就可在重启时根据redo日志中的记录将页面恢复到系统崩溃前的状态。
MySQL根据redo日志的各种信息来确定恢复的起点和终点,redo日志中的数据以哈希表的形式,将一个页面下的放到哈希表的一个槽(slot)中。之后只需遍历哈希表,因为对同一个页面做修改的redo日志都放在了一个槽(slot)里,可以一次性将一个页面修复好,避免了读取页面的随机IO。
3.2、崩溃后为什么不用binlog
binlog会记录表所有更改操作,包括更新删除数据,更改表结构等,主要用于人工恢复数据;而redo log对于用户不可见,是InnoDB用于保证 crash-safe 能力的,及在事务提交后若MysSQL崩溃,可保证事务的持久性,即事务提交后其更改是永久的。
1、binlog是用作人工恢复数据的,redo log是 MySQL 自己使用,用于保证在数据库崩溃时的事务持久性;
2、redo log是 InnoDB 引擎特有的,binlog 是 MySQL 的Server 层实现的,所有引擎都可使用;
3、redo log是物理日志,记录了 在某个数据页上做了什么修改,恢复速度更快;binlog是逻辑日志,记录了 语句的原始逻辑,如 给某条记录的字段做什么修改;
4、redo log是"循环写"的日志文件,redo log只会记录未刷盘的日志,已经刷入磁盘的数据都会从有限大小的 redo log 日志文件中删除;binlog是追加日志,保存的是全量的日志。
5、在数据库crash后,若要恢复未刷盘但已写入 redo log 和 binlog 的数据到内存时,binlog是无法恢复的。binlog虽然拥有全量的日志,但没有一个标志让 InnoDB 判断哪些数据已经入表(写入磁盘),哪些数据还没有。
如:binlog 记录了两条日志:
-- 记录1 update tbl set c = c + 1 where id = 2 ; -- 记录2 update tbl set c = c + 1 where id = 2 ;
记录1入表后,记录2未入表时,数据库crash。重启后,只通过binlog数据库无法判断两条记录哪条已经写入磁盘,哪条未写入磁盘,无论两条记录是否都恢复,对 ID = 2 的行数据而言,都不对。
redo log日志只要输入磁盘的数据,都会从redo log中删除,数据库重启后,直接把redo log中的数据都恢复值内存即可。
2、undo日志
数据库事务四大特性中有一个是 原子性 ,具体来说就是 原子性是指对数据库的一系列操作,要么全部成功,要么全部失败。若事务执行到一半就结束,但是事务执行过程中可能已经修改了很多东西,为了保证事务的原子性,我们需要把东西改回原先的样子,这个过程就称之为回滚(英文名:rollback)。
为了回滚而记录的内容称之为撤销日志,英文名为undo log/undo日志。因为查询操作(SELECT)并不会修改任何用户记录,所以在查询操作执行时,并不需要记录相应的undo日志。
2.1、事务ID
2.1.1、事务分配id的时机
使用 BEGIN、START TRANSACTION 语句开启的事务默认为读写事务,以MySQL5.7描述的事务id分配策略为例:
在读写事务中可以对表执行增删改查操作。若某个事务执行过程中对某个表执行了DML操作,则InnoDB存储引擎会给它分配一个事务id,分配方式如下:
对于读写事务,只有在其第一次对某个表执行DML操作时才会为该事务分配一个事务id,否则不分配事务id;若开启的读写事务中全是查询语句,并没有DML语句此事务并不会被分配一个事务id。
2.1.2、事务id生成机制
事务id本质上是一个数字,具体策略如下:
服务器会在内存中维护一个全局变量,每当需要为某个事务分配一个事务id时,就会把该变量的值当作事务id分配给该事务,并且把该变量自增1;
每当该变量的值为256的倍数时,就会将该变量的值刷新到系统表空间的页号为5的页面中一个称之为Max Trx ID的属性中,该属性占用8个字节的存储空间;
当系统下一次重新启动时,会将上边提到的Max Trx ID属性加载到内存中,将该值加上256之后赋值给全局变量(避免在上次关机时该全局变量可能大于Max Trx ID属性值)。
先被分配id的事务得到的是较小的事务id,后被分配id的事务得到的是较大的事务id。
2.2、隐藏列 trx_id
InnoDB记录行格式中记录除了会保存完整的用户数据外,还会自动添加名为trx_id,roll_pointer的隐藏列,若用户没有在表中定义主键以及UNIQUE键,还会自动添加一个名为row_id的隐藏列。
trx_id列是某个对这个聚簇索引记录做改动的语句所在的事务对应的事务id,此处改动是 INSERT、DELETE、UPDATE 操作。
2.3、undo日志格式
为了实现事务的原子性,InnoDB存储引擎在实际进行增、删、改一条记录时,需要先把对应的undo日志记录下来。一般每对一条记录做一次改动,就对应着一条undo日志,但在某些更新记录操作中,也可能会对应着2条undo日志。
一个事务在执行过程中可能新增、删除、更新若干条记录,即需要记录多条对应的undo日志,undo日志会被从0号开始编号,也就是说根据生成的顺序分别被称为第0号undo日志、第1号undo日志、...、第n号undo日志等,这个编号也被称之为undo no。
2.3.1、INSERT操作对应的undo日志
当我们向表中插入一条记录时最终导致的结果就是这条记录被放到了一个数据页中,若要回滚这个插入操作,那么把这条记录删除就可以了,即在写对应的undo日志时,主要是把这条记录的主键信息记上。InnoDB提供了一个类型为 TRX_UNDO_INSERT_REC 的 undo 日志。
InnoDB存储引擎的表而言,它的聚簇索引记录中都包含两个必要的隐藏列:
·trx_id:每次一个事务对某条聚簇索引记录进行改动时,都会把该事务的事务id赋值给trx_id隐藏列;
·roll_pointer:每次对某条聚簇索引记录进行改动时,都会把旧的版本写入到undo日志中,这个隐藏列就相当于一个指针,通过它来找到该记录修改前的信息。
roll_pointer本质上是一个指向记录对应的undo日志的一个指针,指向记录对应的undo日志。比如向表里插入2条记录,每条记录都有与其对应的一条undo日志。记录被存储到了类型为 FIL_PAGE_INDEX 的页面中,undo日志被存放到了类型为 FIL_PAGE_INDEX 的页面中。
2.3.2、DELETE操作对应的undo日志
插入到页面中的记录会根据记录头信息中的 next_record 属性组成一个单向链表,这个链表称之为正常记录链表。
往表中插入多条记录时,每次对记录进行改动,都会记录一条undo日志,每条undo日志也都有一个roll_pointer属性(INSERT 操作对应的undo日志没有该属性,因为该记录并没有更早的版本),可将这些undo日志都连起来,串成一个链表。
被删除的记录其实也会根据记录头信息中的 next_record 属性组成一个链表,该链表中的记录占用的存储空间可以被重新利用,这个链表被称为垃圾链表。
Page Header部分有一个称为 PAGE_FREE 属性,它指向由被删除记录组成的垃圾链表中的头节点。
若某个页面中的记录分布详情如下:
将记录的delete_mask标志位展示出来,正常记录链表中包含了3条正常记录,垃圾链表里包含了2条已删除记录了。页面的Page Header部分的 PAGE_FREE 属性的值代表指向垃圾链表节点的指针。
若准备使用DELETE语句把正常记录链表中的最后一条给删除掉,其实这个删除的过程需要经历两个阶段:
阶段一:将记录的delete_mask标识位设置为1,这个阶段称之为delete mask。
正常记录链表中的最后一条记录的delete_mask值被设置为1,但是并没有被加入到垃圾链表。此时记录处于一个中间状态,在删除语句所在的事务提交之前,被删除的记录一直都处于中间状态。
这种中间状态,主要是为了实现MVCC中的事务隔离级别。
阶段二:当该删除语句所在的事务提交之后,会有专门的线程后来真正的把记录删除掉。真正的删除就是把该记录从正常记录链表中移除,并且加入到垃圾链表中,然后还要调整一些页面的其他信息。如页面中的用户记录数量 PAGE_N_RECS、上次插入记录的位置 PAGE_LAST_INSERT、垃圾链表头节点的指针 PAGE_FREE、页面中可重用的字节数量 PAGE_GARBAGE、还有页目录的一些信息等。该阶段称之为 purge。
阶段二执行完成后,该条记录就算是真正的被删除掉了。这条已删除记录占用的存储空间可被重新利用。
在删除语句所在事务提交之前,只会经历阶段一,即delete mark阶段(提交后不用回滚,只需考虑对删除操作的阶段一做的影响进行回滚)。InnoDB中会产生一种称之为 TRX_UNDO_DEL_MARK_REC 类型的 undo 日志。
版本链:
在对一条记录进行delete mark操作前,需要把该记录的旧的 trx_id 和 roll_pointer 隐藏列的值都给记到对应的undo日志中来,就是 old_trx_id 和 old_roll_pointer 属性。如此,可以通过undo日志的 old_roll_pointer 找到记录在修改之前对应的undo日志。如在一个事务中,先插入一条记录,然后又执行对该记录的删除操作,示意图如下:
执行delete mark操作后,其对应的undo日志和INSERT操作对应的undo日志就串成了一个链表,该链表称之为版本链。
2.3.3、UPDATE操作对应的undo日志
在执行UPDATE语句时,InnoDB对更新主键和不更新主键有两种处理方案。
3.1、不更新主键
不更新主键的情况,可以细分为被更新的列占用的存储空间不发生变化和发生变化的情况。
· 就地更新(in-place update)
更新记录时,对于被更新的每个列来说,如果更新后的列和更新前的列占用的存储空间都一样大,那么就可以进行就地更新,也就是直接在原记录的基础上修改对应列的值。
每个列在更新前后占用的存储空间一样大,有任何一个被更新的列更新前比更新后占用的存储空间大,或者更新前比更新后占用的存储空间小都不能进行就地更新。
· 先删除掉旧记录,再插入新记录
在不更新主键的情况下,如果有任何一个被更新的列更新前和更新后占用的存储空间大小不一致,那么就需要先把这条旧的记录从聚簇索引页面中删除掉,然后再根据更新后列的值创建一条新的记录插入到页面中。
这里的删除并不是delete mark操作,是真正的删除,即把这条记录从正常记录链表中移除并加入到垃圾链表中,并且修改页面中相应的统计信息。由用户线程同步执行真正的删除操作,真正删除之后紧接着就要根据各个列更新后的值创建的新记录插入。
若新创建的记录占用的存储空间大小不超过旧记录占用的空间,则可以直接重用被加入到垃圾链表中的旧记录所占用的存储空间,否则需要在页面中新申请一段空间以供新记录使用,如果本页面内已经没有可用的空间的话,那就需要进行页面分裂操作,然后再插入新记录。
针对UPDATE不更新主键的情况(包括上边所说的就地更新和先删除旧记录再插入新记录),InnoDB提供了类型为TRX_UNDO_UPD_EXIST_REC的undo日志。
3.2、更新主键
3.2.1、更新主键的情况
在聚簇索引中,记录是按照主键值的大小连成了一个单向链表,若更新了某条记录的主键值,就表示这条记录在聚簇索引中的位置将会发生改变。
在聚簇索引中,记录是按照主键值的大小连成了一个单向链表的,如果我们更新了某条记录的主键值,意味着这条记录在聚簇索引中的位置将会发生改变,比如你将记录的主键值从1更新为10000,如果还有非常多的记录的主键值分布在1 ~ 10000之间的话,那么这两条记录在聚簇索引中就有可能离得非常远,甚至中间隔了好多个页面。针对UPDATE语句中更新了记录主键值的这种情况,InnoDB在聚簇索引中分了两步处理:
1、旧记录进行delete mark操作
在UPDATE语句所在的事务提交前,对旧记录只做一个delete mark操作,在事务提交后才由专门的线程做purge操作,把它加入到垃圾链表中。
只对就记录做delete mark操作,是因为别的事务同时也可能访问这条记录,如果把它真正的删除加入到垃圾链表后,别的事务就访问不到了。这个功能就是所谓的MVCC。
2、创建一条新记录
根据更新后各列的值创建一条记录,并将其插入到聚簇索引中(需重新定位插入的位置)。
由于更新后的记录主键值发生了改变,所以需要重新从聚簇索引中定位这条记录所在的位置,然后把它插进去。
针对UPDATE语句更新记录主键值的这种情况:
在对该记录进行delete mark操作前,会记录一条类型为TRX_UNDO_DEL_MARK_REC的undo日志;
之后插入新记录时,会记录一条类型为TRX_UNDO_INSERT_REC的undo日志,也就是说每对一条记录的主键值做改动时,会记录2条undo日志。
3、二进制日志 binLog
binlog 用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在磁盘中。binlog 是 mysql的逻辑日志,并且由 Server 层进行记录,使用任何存储引擎的 mysql 数据库都会记录 binlog 日志。
逻辑日志 :可以简单理解为记录的就是sql语句 。
物理日志 :mysql 数据最终是保存在数据页中的,物理日志记录的就是数据页变更 。
binlog 是通过追加的方式进行写入的,可以通过max_binlog_size 参数设置每个 binlog文件的大小,当文件大小达到给定值之后,会生成新的文件来保存日志。
3.1、bingLog的使用场景
在实际应用中, binlog 的主要使用场景有两个,分别是 主从复制 和 数据恢复 。
主从复制 :在 Master 端开启 binlog ,然后将 binlog发送到各个 Slave 端, Slave 端重放 binlog 从而达到主从数据一致。
数据恢复 :通过使用 mysqlbinlog 工具来恢复数据。
3.2、binlog刷盘时机
对于 InnoDB 存储引擎而言,只有在事务提交时才会记录biglog ,此时记录还在内存中,那么 biglog是什么时候刷到磁盘中的呢?
mysql 通过 sync_binlog 参数控制 biglog 的刷盘时机,取值范围是 0-N:
0:不去强制要求,由系统自行判断何时写入磁盘;
1:每次 commit 的时候都要将 binlog 写入磁盘;
N:每N个事务,才会将 binlog 写入磁盘。
从上面可以看出, sync_binlog 最安全的是设置是 1 ,这也是MySQL 5.7.7之后版本的默认值。但是设置一个大一些的值可以提升数据库性能,因此实际情况下也可以将值适当调大,牺牲一定的一致性来获取更好的性能。
3.3、binlog日志格式
binlog 日志有三种格式,分别为 STATMENT 、 ROW 和 MIXED。在 MySQL 5.7.7 之前,默认的格式是 STATEMENT , MySQL 5.7.7 之后,默认值是 ROW。日志格式通过 binlog-format 指定。STATMENT:基于SQL 语句的复制( statement-based replication, SBR ),每一条会修改数据的sql语句会记录到binlog 中 。
3.4、redo log与binlog区别
由 binlog 和 redo log 的区别可知:binlog 日志只用于归档,只依靠 binlog 是没有 crash-safe 能力的。
但只有 redo log 也不行,因为 redo log 是 InnoDB特有的,且日志上的记录落盘后会被覆盖掉。因此需要 binlog和 redo log二者同时记录,才能保证当数据库发生宕机重启时,数据不会丢失。
标签:事务,log,记录,笔记,undo,日志,redo,底层 From: https://www.cnblogs.com/RunningSnails/p/18061671