Undo log 是 MySQL 实现事务的关键机制之一。
Undo log 是事务原子性和一致性的保证,在事务中更新数据的前置操作,其实就是要先写入一个 Undo Log 。
本文将通过技术原理图解析:Undo Log 的存储机制、工作原理。
01Undo log 的概念及作用
Undo log 以逻辑方式记录数据库事务的修改操作,它记录了事务执行过程中旧值的备份,以便在事务回滚或并发控制需要时能够恢复数据。
当我们执行一条 insert 语句时,Undo Log 就会记录一条相反的 delete 语句。
例如:
假设在用户付款过程中,发现付款金额错误,此时就需要回滚事务并使用 Undo log 中记录的旧值来恢复正确的付款金额。
-- 在事务中更新付款金额
BEGIN;
UPDATE payments SET amount = 100.00 WHERE id = 1;
-- 假设发现付款金额错误,需要回滚事务并恢复旧值
ROLLBACK;
通过回滚事务并使用 Undo log 中记录的旧值,将数据库中的付款金额恢复到事务开始之前的状态,保证了数据的一致性。
02 Undo log 的两大作用
- 事务回滚:数据回滚操作(事务的原子性实现),在事务执行过程中,如果出现错误或需要回滚操作,Undo log 可以恢复事务执行之前的数据状态,实现事务的回滚操作。
- 并发控制:实现 MVCC 多版本并发控制,通过 Undo log 可以实现数据库并发事务的隔离性和一致性,避免数据读取和写入的冲突。
03 Undo log 的存储机制
Undo Log 存储采用分段(segment)的方式管理和记录。
Undo log 的存储控制可以通过下面这条参数实现:
show variables like '%innodb_undo%';
在 InnoDB 存储数据的文件中,包含了一种回滚段(Rollback Segment),每个回滚段中有 1024 个 Undo log segment(版本 5.5 后,可以支持 128 个 Rollback Segment)。
每个回滚段都对应一个或多个 Undo log 日志文件,用于记录事务执行前的数据快照、以及存储事务操作的详细信息,例如插入、更新或删除。
下面通过图例,进一步理解 Undo log 的存储机制:
在 undo log 中,存放着数据更新前的记录,以及 RowID、事务ID、回滚指针的记录。
事务 ID 每次递增,如果回滚指针第一次是 insert 语句,回滚指针为 NULL,在第二次 update 之后,undo log 的回滚指针就会指向刚才的 undo log 日志。
以此类推,就形成了 undo log 的回滚链,这样就能十分便捷地查询到该条记录的历史版本了。
04 Undo log 的工作原理
Undo Log 属于逻辑日志,记录一个变化过程。例如:
- 执行一个 delete,Undo log 会记录一个 insert;
- 执行一个 update,Undo log 会记录一个相反的 update。
在更新数据之前,MySQL 会提前生成 Undo Log 日志,在事务提交时不会立即删除 Undo Log,原因是之后可能还需要进行回滚操作,在执行回滚(ROLLBACK)操作时从缓存中读取数据。
Undo Log 日志的删除,是通过后台 purge 线程进行回收处理的。
下面用一张图来帮助理解,看一条 SQL 执行 update、select 的详细过程:
- 事务 A:执行更新操作,先将更新命中的数据备份到对应的 undo buffer,再由 undo buffer 持久化到磁盘中的 undo log 文件。
- 事务 B:进行查询操作,从 undo buffer 缓存中直接读取,若回滚(rollback)事务,先从 undo buffer 缓存直接读取,不需要读磁盘。
05 总结
通过本文,我们了解并掌握了 Undo log 的储存机制以及工作原理。
Undo log 是 MySQL 中极为重要的一种逻辑日志,Undo log 以逻辑方式记录数据库事务的修改操作,记录了事务执行过程中旧值的备份,以便在事务回滚或并发控制需要时能够恢复数据。
正确使用 Undo log ,可以极大地提高数据库的性能和并发控制能力。