MySQL的事务日志:

目录

redo(重做日志):

特点:

组成:

整体流程:

[redo log buffer与redo log file之间的刷盘策略:](#redo log buffer与redo log file之间的刷盘策略:)

异步刷盘:

同步刷盘:

拆中策略:

undo(回滚日志):

存储结构:

undo页的重用:

回滚段与事务:

回滚段中的数据分类:

未提交的回滚数据:

已经提交但未过期的回滚数据:

事务已经提交并过期的数据:

生成过程:

类型分类:

[insert undo log:](#insert undo log:)

[update undo log:](#update undo log:)

undo删除:

[insert undo log:](#insert undo log:)

[update undo log:](#update undo log:)

总结:


事务的隔离由锁机制实现,而事务的原子性、一致性和持久性是由事务的redo日志和undo日志来保证。其中redo是指重做日志,是存储引擎生成的日志,记录的是"物理级别"上的页修改操作,提供再写入操作,回复提交事务修改的页操作,用于保证事务的持久性。undo日志是指回滚日志,是存储引擎层生成的日志,记录的是逻辑操作日志,回滚行记录到某个特定的版本,用于保证事务的原子性、一致性。

redo(重做日志):

InnoDB存储引擎是以页为单位来管理存储空间的,在访问页面之前,需要把磁盘上的页缓存到内存中的缓冲池里面才可以访问。所有的变更都必须先更新缓冲池中的数据,然后缓冲池中的脏页(内存中修改了而磁盘中还未修改的数据页)会一定的频率被刷入磁盘,通过缓冲池来优化CPU和磁盘之间的交互。

InnoDB存储引擎的事务采用了WAL技术,WAL技术的思想是先写日志,再写磁盘,只有当日志写入成功,才算事务提交成功,而这里的日志指的是redo日志。当事务提交成功之后,还没有进行刷盘时,发生了宕机,就可以通过redo日志来进行恢复数据。

优点是:降低了刷盘的频率(不用去维持实时刷新磁盘),占用的空间非常小(存储表空间id,页号,偏移量以及需要更新的值,所以存储空间很小,而且刷盘速度快)。

特点:

redo日志是顺序写入磁盘的,在执行事务的过程中,每执行一条语句,就可能产生若干条redo日志,这些日志是按照产生的顺序写入磁盘的,使用顺序IO,效率比随机IO快。

事务执行过程中,redo不断记录,在事务执行过程中,是一直不断地往redo顺序记录,直到事务提交。

组成:

重做日志的缓冲(redo log buffer),保存在内存中,是易丢失。服务器启动时就向操作系统申请了一大片重做日志的缓冲的连续内存空间,也就是redo日志缓冲区,这片内存空间被分成很多连续的redo log block,一个占用512字节。

重做日志文件(redo log file),保存在硬盘中,是持久的。

整体流程:

先将原数据从磁盘中读入内存中,修改数据的内存拷贝。

生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值。

当事务提交时,将redo log buffer中的内存刷新到redo log file,对redo log file采用追加写的方式。

定期将内存中修改的数据刷新到磁盘中。

redo log buffer与redo log file之间的刷盘策略:

重做日志缓冲刷盘到重做日志文件不是真正的刷到磁盘中去,只是刷入到文件系统缓存中,真正的写入由系统决定。而此时InnoDB就存在一个问题,如果系统宕机了,那么数据也会丢失。

所以针对这种情况,给出了一个innodb_flush_log_at_trx_commit参数来控制commit提交事务时,如何将重做日志缓冲中的日志刷新到重做日志文件中。

异步刷盘:

1.当innodb_flush_log_at_trx_commit=0时,表示每次事务提交时不进行刷盘操作。

InnoDB中有一个后台线程,每隔1秒,会把重做日志缓冲中的内容写道文件系统缓存中,然后调用刷盘操作。如果崩溃的话,可能会丢失1秒内的已提交事务数据。事务提交之后,不需要等待刷盘。

当一个没有提交事务的重做日志记录,也可能会刷盘。因为在事务执行过程中重做日志记录会写入到重做日志缓冲中,而这些记录会被后台线程刷盘。

当重做日志缓冲占用的空间即将达到innodb_log_buffer_size的一半时,后台线程会主动刷盘。

如果事务最终未提交或者崩溃恢复时,会通过undo日志回滚已刷盘的的未提交数据,保证数据的原子性。

同步刷盘:

2.当innodb_flush_log_at_trx_commit=1时,表示每次事务提交时都将进行同步刷盘操作。(默认值)

只要事务提交成功,重做日志记录一定在硬盘中,不会有任何数据丢失。如果事务执行期间宕机,相对应的部分日志丢失,但是事务并没有提交,所以日志丢失也不会造成损失,可以保证持久性,数据不会丢失,但是效率最差,因为事务提交之后需要等待重做日志缓冲中的内容写入到文件系统缓存中同时还要进行刷盘。

拆中策略:

3.当innodb_flush_log_at_trx_commit=2时,表示每次事务提交时都只把重做日志缓冲内容写入到文件系统缓存中,不进行同步。由操作系统决定同步到磁盘文件中的时间。后台线程以一定的时间间隔进行一次将文件系统缓存中的内容写入到磁盘中。事务提交之后,需要将重做日志缓存中的内容写入到文件系统缓存中,不需要等待刷盘。性能介于异步刷盘和同步刷盘之间。

如果操作系统宕机,文件系统缓存可能会有数据丢失,就无法满足持久性。

undo(回滚日志):

在事务更新数据的前置操作要先写入一个回滚日志。

undo是逻辑日志,只是将数据库逻辑地恢复到原来的样子,但是数据结构和页本身在回滚之后可能不相同。

回滚日志也会产生重做日志,因为回滚日志也需要持久性的保护。

存储结构:

InnoDB对undo的管理采用段的方式,也就是回滚段,每个回滚段记录1024个undo log segment,在每个undo log segment段中进行undo页的申请。

undo页的重用:

当开启一个事务需要写undo日志时,就得去undo log segment中找空闲的位置,当有空闲位置时,就去申请undo页,这样的话,每开启一个事务就申请一个页,很浪费存储空间。所以可以对undo页进行判断是否可以重用。

当事务提交时,并不会立刻删除undo页,因为undo页的重用一个undo页可能混杂着其他事务的undo log。undo log在事务提交后,会被放到一个链表中,然后判断undo页的使用空间是否小于3/4,如果小于,则表示当前的undo页可以被重用,就不会被回收,其他事务的undo log可以记录在当前的undo页后面,由于undo页是离散的,所以清理对应的磁盘空间时,效率不高。

回滚段与事务:

每个事务只会使用一个回滚段,一个回滚段在同一时刻可能会服务多个事务。

当一个事务开始时,会制定一个回滚段,在事务进行的过程中,数据被修改时,原始的数据会被覆盖到回滚段中。

在回滚段中,事务会不断填充盘区,直到事务结束或者空间被用完。如果当前盘区不够用,那么事务会在段中请求扩展到下一个盘区,如果已分配的盘区都用完,事务会覆盖最初的盘区或者在回滚段允许的情况下扩展新的盘区来使用。

回滚段存在于undo表空间中,在数据库中可以存在多个undo表空间,但同一时刻只能使用一个undo表空间。

当事务提交时,InnoDB存储引擎会将undo log放到列表中,以方便之后的清除操作,还会判断undo log所在的页是否可以重用,若可以则分配给下一个事务使用。

回滚段中的数据分类:

未提交的回滚数据:

该数据所关联的事务未提交,用于实现读一致性,所以该数据不能被其他事务的数据覆盖。对应事务的活动状态或者部分提交状态。

已经提交但未过期的回滚数据:

该数据关联的事务已经提交,但是仍受到undo retention参数的保持时间的影响。也就是事务提交之后,undo日志未被清理线程清理,主要针对的是update undo log。

事务已经提交并过期的数据:

该数据关联的事务已经提交,而且数据保存时间已经超过undo retention参数指定的时间,属于已经过期的数据。也就是事务提交之后,undo日志不再被MVCC依赖,清理线程通过扫描链表清理了过期条目。当回滚段满了之后,会优先覆盖"事务已经提交并过期的数据"。

事务提交之后不能马上删除undo log以及undo log所在的页,因为可能还有在其他事务需要通过undo log来得到行之前的版本,事务提交时,会将undo log放入一个链表中。

生成过程:

InnoDB存储引擎中有几个隐藏的列:

DB_ROW_ID:如果没有主键且没有唯一索引,那么会自动添加一个隐藏列作为主键。

DB_TRX_ID:每个事务都会分配一个事务ID,当对某条记录进行变更时,就会将这个事务ID写入trx_id中。

DB_ROLL_PTR:回滚指针,指向undo log的指针。

当插入一条数据时,会生成一条undo log,记录着undo log的序号、插入主键的列和值等信息,在进行回滚时,直接通过主键把对应的数据删除即可。

更新操作会分更新主键和不更新主键的情况,

如果是不更新主键,就把此次更新之前的数据写入到新的undo log中,让回滚指针指向新的undo log,让新的undo log指向旧的undo log,可以参考链表的头插法。

如果是更新主键的操作,那么会把逻辑删除的标识从0置为1,这个改变也需要通过一个undo log进行记录头插到该记录的回滚指针后面,然后在此条记录后面插入一条新的记录且新的记录的回滚指针指向的是主键更新前的记录,新的记录会产生undo log且undo log序号会递增。

类型分类:

insert undo log:

仅处理insert操作新增的数据,用于事务回滚时删除新插入的数据。回滚时根据主键直接删除对应行。

update undo log:

记录update和delete操作修改前的数据状态,支持回滚与快照读。update:保存被修改字段的旧值,delete:存储整行数据的原始内容。

undo删除:

insert undo log:

因为insert操作记录,只对本事务可见,所以可以在事务提交后进行删除。

update undo log:

该undo log可能需要提供MVCC机制,因此不能在事务提交时,就进行删除,需要放到链表当中,等待清理线程进行最后的删除。

总结:

目标数据如果不在缓存池中,将磁盘中的数据页写入到内存缓冲池中,将原数据写入到undo日志中便于回滚,进行数据的更新操作,会将对应的数据写入到redo日志缓存当中,当提交事务时,根据设定的刷盘策略来进行刷盘,将内存中的脏页刷到磁盘当中。如果未提交或者事务崩溃,那么则根据undo日志进行一个数据回滚,恢复至原数据,保证数据的可靠性。

相关推荐
松涛和鸣几秒前
72、IMX6ULL驱动实战:设备树(DTS/DTB)+ GPIO子系统+Platform总线
linux·服务器·arm开发·数据库·单片机
likangbinlxa18 分钟前
【Oracle11g SQL详解】UPDATE 和 DELETE 操作的正确使用
数据库·sql
r i c k1 小时前
数据库系统学习笔记
数据库·笔记·学习
野犬寒鸦1 小时前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
IvorySQL2 小时前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·2 小时前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
IT邦德2 小时前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫2 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写
不爱缺氧i3 小时前
完全卸载MariaDB
数据库·mariadb
纤纡.3 小时前
Linux中SQL 从基础到进阶:五大分类详解与表结构操作(ALTER/DROP)全攻略
linux·数据库·sql