MySQL面试题 事务实现全解析:Undo Log、Redo Log、锁与 MVCC 协同机制详解

MySQL是如何实现事务的?

MySQL有四大特性分别是原子性一致性持久性隔离性

MySQL实现事务靠Undo logRedo logMVCC这四个核心组件来实现的

  1. 通过Undo log来实现原子性,在进行写操作之前,会把原来的数据存入Undo log中,当事务回滚时,通过Undo log进行反向操作,把数据恢复回去。
  2. 通过Redo log 来实现持久性,在进行写操作时,不会直接把数据写入磁盘数据页,而是先写入Redo log,就算写入磁盘数据页宕机了,也能通过重做Redo log来恢复数据。
  3. 通过锁机制来实现写的隔离性,当两个事务同时改一个数据时,必须一个等另一个释放锁,InnoDB支持行锁,间隙锁防止幻读。
  4. 通过MVCC来实现读写的隔离性,读的时候不加锁,而是通过Undo log版本链来找到自己读的数据版本,读的时候能写,写的时候也能读。

Redo log的工作原理

  • InnoDB在写入数据时,不会直接把数据写入磁盘的数据页,因为这样做随机磁盘IO太多,性能不好,而是先把数据顺序写入Redo log中,再找时间把数据页刷到磁盘上,应为顺序写比随机写快。
  • redo log是通过循环写来实现的,redo log中有两个指针,一个记录写到哪里了,一个记录刷盘刷到哪里了,两指针之间就是待刷盘的脏数据。
  • 事务提交时,redo log必须落盘,这个行为由 innodb_flush_log_at_trx_commit 控制:
    • 设置成1,每次提交都要刷盘
    • 设置成0,每一秒刷一次盘,宕机可能造成一秒的数据丢失
    • 设置成2,把数据写到系统缓存中,MySQL宕机不丢失,服务器挂了才丢。

Undo log与版本链

  1. 数据库每条记录都有两个隐藏字段:
    • trx_id:记录最后修改这个数据的事务ID
    • roll_pointer:指向undo log里的上一个版本
  2. 多次修改就会形成一个版本链
  3. MVCC在读数据时,会根据事务的ReadView去沿着版本链去往回找。
  4. 在读未提交的事务隔离级别下,每次访问都会生成新的ReadView;在读已提交下,事务开始时会生成ReadView,以后每次访问都用这个。

事务提交的两个阶段

InnoDB和Server层各有自己的日志,redo log 和bin log,为了保证两个日志的一致性,所以用到了两个阶段。

  1. 准备阶段:redo log写盘,然后把状态改为prepare
  2. 提交阶段:bin log写盘,然后redo log状态改为commit
    如果是bin log写入前宕机,redo log的状态为prepare,但是没有对应的bin log,则触发回滚
    如果是bin log写入后宕机,redo log的状态为prepare,有对对应的bin log,则会触发事务提交
    这一套机制保护了主从复制的数据一致性,主表靠redo log数据恢复,从表靠bin log数据同步。

锁的实现细节

InnoDB的行锁是加在索引上的,如果修改数据时没有走索引,就会锁住整张表

InnoDB有三种行锁:

  • 普通的行锁,锁整行数据
  • 间隙锁:锁一个区间,不包含数据本身
  • 临键锁(行锁+间隙锁):锁整行数据+数据前面的区间

MVCC是什么

MVCC是多版本并发控制,核心思想是让读写互不阻塞:写操作会产生新的版本,读操作会根据事务的ReadView在Undo log的版本链上找到自己版本的数据。

  • 表中的每条数据都有两个隐藏字段,一个记录当前事务ID,一个记录undo log
  • 每次写操作,都会先把旧的值写入undo log,再把新的值写入磁盘数据页,回滚指针指向旧版本,这样就形成了一个数据链。
  • 普通的读都是快照读,不加锁,直接通过版本链找到自己对应的数据直接返回。

MySQL 中的日志类型有哪些?bin log、redo log 和 undo log 的作用和区别是什么?

MySQL 有三种核心日志。bin log 负责主从复制和数据恢复,redo log 保证崩溃后数据不丢,undo log 支撑事务回滚和 MVCC。

  • bin log 是 Server 层的日志,记录的是逻辑操作,也就是原始 SQL 或者行变更前后的值。它的核心场景是主从同步,从库拉取主库的 bin log 重放一遍就能保持数据一致。另外做数据恢复的时候,也是靠 bin log 配合全量备份回放到指定时间点。

  • redo log 是 InnoDB 引擎独有的,记录的是物理变更,具体就是"某个数据页的某个偏移量改成了什么值"。它的作用是 MySQL 挂了重启后,InnoDB 会用 redo log 把没来得及刷盘的脏页恢复出来。redo log 是循环写的,空间固定,写满了就得等 checkpoint 推进才能继续。

  • undo log 也是 InnoDB 的,记录的是数据修改前的旧值。事务回滚的时候,就靠 undo log 把数据改回去。另外 MVCC 的快照读也依赖它,别的事务要读历史版本,顺着 undo log 链往前找就行。

相关推荐
txinyu的博客2 小时前
MySQL 学过但是全忘了?15min帮你快速复习
数据库·mysql
数据知道2 小时前
如何使用 httpx + SQLAlchemy 异步高效写入上亿级图片链接与MD5到 PostgreSQL
数据库·postgresql·httpx
PeterClerk2 小时前
数据挖掘方向 CCF 期刊推荐(数据库 / 数据挖掘 / 内容检索)
数据库·人工智能·深度学习·数据挖掘·计算机期刊
littlegirll2 小时前
一个KADB使用gpbackup迁移数据的脚本
数据库·数据迁移·kadb·gpbackup
alonewolf_992 小时前
Redis Stack全面解析:从JSON存储到布隆过滤器,打造高性能Redis扩展生态
数据库·redis·json
正在走向自律10 小时前
金仓数据库KingbaseES中级语法详解与实践指南
数据库·oracle·kingbasees·金仓数据库·信创改造
Gofarlic_oms110 小时前
Windchill用户登录与模块访问失败问题排查与许可证诊断
大数据·运维·网络·数据库·人工智能
我是小疯子6610 小时前
Python变量赋值陷阱:浅拷贝VS深拷贝
java·服务器·数据库
Zoey的笔记本11 小时前
2026告别僵化工作流:支持自定义字段的看板工具选型与部署指南
大数据·前端·数据库