undo log 日志详解

undo log 记录的是数据的事务开始之前的一个版本,可用于事务失败之后发生的回滚。

1. undo log的操作介绍

在数据修改的时候,不仅记录了redo,还记录了相对应的undo,如果因为某些原因导致事务失败或回滚了,可以借助该undo log进行回滚。

undo log和redo log记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。

当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。有时候应用到行版本控制的时候,也是通过undo log来实现的:当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据是什么,从而提供该行版本信息,让用户实现非锁定一致性读取。

undo log是采用段(segment)的方式来记录的,每个undo操作在记录的时候占用一个undo log segment。

另外,undo log也会产生redo log,因为undo log也要实现持久性保护。

delete/update操作的内部机制

当事务提交的时候,innodb不会立即删除undo log,因为后续还可能会用到undo log,如隔离级别为repeatable read时,事务读取的都是开启事务时的最新提交行版本,只要该事务不结束,该行版本就不能删除,即undo log不能删除。

但是在事务提交的时候,会将该事务对应的undo log放入到删除列表中,未来通过purge来删除。并且提交事务时,还会判断undo log分配的页是否可以重用,如果可以重用,则会分配给后面来的事务,避免为每个独立的事务分配独立的undo log页而浪费存储空间和性能。

通过undo log记录delete和update操作的结果发现:(insert操作无需分析,就是插入行而已)

  1. delete操作实际上不会直接删除,而是将delete对象打上delete flag,标记为删除,最终的删除操作是purge线程完成的。
  2. update分为两种情况:update的列是否是主键列。
    1. 如果不是主键列,在undo log中直接反向记录是如何update的。即update是直接进行的。
    2. 如果是主键列,update分两部执行:先删除该行,再插入一行目标行。

Redo Log记录的是具体某个数据页上的修改,只能在当前Server使用,而Binlog可以理解为可以给其他类型的存储引擎使用。这也是Binlog的一个重要作用,那就是主从复制,另外一个作用是数据恢复

2.多版本并发控制(MVCC)

InnoDB为数据库中的每一行添加了三个隐藏字段:DB_TRX_ID(事务版本号)、DB_ROLL_PTR(回滚指针)、DB_ROW_ID(隐藏ID)。

  1. DB_TRX_ID:记录了创建/更新这条数据的事务版本号(版本号会递增)。
  2. DB_ROLL_PTR:记录了一个指向undo log中历史版本的数据指针。(用来支持回滚操作)
  3. DB_ROW_ID:一个自增的隐藏行ID。

InnoDB基于事务版本号、回滚指针这两个字段,可以在undo log中形成一个单向链表,最新版本的数据放在链表头部,历史数据通过DB_ROLL_PTR(回滚指针)指针进行关联。如下图所示

有了这种结构的数据后,InnoDB可以很方便的管理多个版本的数据,也为MVCC的实现打下来基础。

2.1 MVCC解决了哪些问题?
MVCC可以解决脏读、不可重复读,并且实现了非阻塞读的功能。

MVCC在InnoDB中具体的实现逻辑是怎样的,以及MVCC解决了哪些问题。

首先,InnoDB在事务开启后执行第一个查询时,会创建一个快照(下文称之为ReadView),这个ReadView包含了以下信息:

m_ids: 活动事务id列表(活动事务指的是已经开始、尚未提交/回滚的事务)

min_trx_id: 最小活动事务id

max_trx_id:最大活动事务id

creator_trx_id:当前事务id

紧接着InnoDB会通过查询语句定位到最新版本的数据行,并根据以下规则获取到可以访问的数据版本。

        如果被访问版本的trx_id,与readview中的creator_trx_id值相同,表明当前事务在访问自己修改过的记录,直接返回该版本的数据;

        如果被访问版本的trx_id,小于readview中的min_trx_id值,表明生成该版本的事务在当前事务生成readview前已经提交,直接返回该版本的数据;

        如果被访问版本的trx_id,大于或等于readview中的max_trx_id值,表明生成该版本的事务在当前事务生成readview后才开启,此时该版本不可以被当前事务访问,需要通过隐藏的回滚指针从undo log中读取历史版本;

        如果被访问版本的trx_id,在readview的min_trx_id和max_trx_id之间,则需要判断trx_id值是否在m_ids列表中?

                如果在:说明readview创建时,创建该版本数据的事务还未提交,因此需要通过回滚指针读取历史版本并返回。

                如果不在:说明readview创建时,创建该版本数据的事务已经提交,所以直接返回该版本的数据;

读已提交隔离级别下:每次查询都会创建一个新的ReadView。新建的ReadView会更新creator_trx_id以外的其余字段,所以每次读操作都会设置和读取自己的新快照(ReadView),因此不可重复读现象依然存在。

可重复读隔离级别下:ReadView只会在第一次查询时创建,同一个事务中后续所有的查询共用一个ReadView,由此便解决了不可重复读的问题。

但是由于ReadView可以判断出修改此数据的事务是否已经提交,因此可以避免脏读的出现。

其次,从上述MVCC实现逻辑中可以发现,没有任何加锁、获取锁的操作,因此MVCC读操作不会因为等待锁而阻塞(也就是常说的非阻塞读)。

总结:

        MVCC可以解决脏读、不可重复读,并且实现了非阻塞读的功能。

2.2 当前读与快照读

Mysql中的读操作可以分为两大类:快照读与当前读。

快照读是指通过MVCC实现的非阻塞读,常见的快照读操作如下:

select * from xxx

当前读也叫加锁读,每次读取数据都是读取数据的最新版本,并且会对其进行加锁。常见的当前读操作如下

select * from xxx lock in share mode (共享锁/读锁)
select * from xxx for update (排它锁/写锁)
update 、delete、insert

为什么要区分这两种读操作呢?因为MVCC并不能解决幻读的问题。即使是在可重复读级别,通过当前读依然会出现幻读问题。此问题最终是通过间隙锁来解决的。

  • 13
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BinlogUndo Log和Redo Log是三种常见的日志文件类型。 BinlogMySQL数据库中的二进制日志文件,它记录了所有对数据库的修改操作,包括增删改等。Binlog以追加的方式进行写入,并可以通过设置max_binlog_size参数来控制每个binlog文件的大小。当文件大小达到给定值后,会生成新的文件来保存日志。Binlog的主要用途是用于数据备份、数据恢复以及数据库复制的过程中。 Undo Log是用于回滚操作的日志文件,记录了事务执行过程中对数据的修改操作。当事务进行回滚操作时,Undo Log中的日志记录会被用来还原事务执行前的数据状态。Undo Log的存储格式可以根据数据库的实现方式而有所不同。 Redo Log是用于事务的持久性和恢复操作的日志文件。它记录了事务执行过程中对数据的修改操作,并在事务提交前将这些操作持久化到磁盘上。当数据库发生故障时,Redo Log可以通过重做操作来恢复数据的一致性。Redo Log的格式通常是固定的,如MySQL中的Redo Log文件名为ib_logfileN。 综上所述,Binlog记录数据库的修改操作的二进制日志文件,Undo Log记录事务回滚操作的日志文件,而Redo Log是用于事务的持久性和恢复操作的日志文件。它们在存储内容、格式、生成方式以及使用场景上都有一定的区别。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [MySQL的redo logundo log、binlog](https://download.csdn.net/download/weixin_38619613/13686869)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [mysql_三大日志binlog、redoLogundoLog详解](https://blog.csdn.net/chuige2013/article/details/123027580)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值