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 链往前找就行。

相关推荐
ccddsdsdfsdf7 小时前
DBeaver怎么链接mongoDB
数据库·mongodb
丷丩8 小时前
Postgresql基础实践教程(十一)各种Join
数据库·postgresql·join
星夜夏空998 小时前
FreeRTOS学习(4)——内存映射
数据库·学习·mongodb
TheRouter8 小时前
AI Agent 记忆体系建设实战:短期、长期与工作记忆的工程实现
数据库·人工智能·oracle
Omics Pro9 小时前
首个!外源天然产物综合性代谢图谱
数据库·人工智能·算法·机器学习·r语言
唐青枫9 小时前
MySQL EXISTS 详解:存在性判断、NOT EXISTS 与实战示例
sql·mysql
JAVA面经实录91710 小时前
Hibernate面试题库
数据库·oracle·hibernate
2301_7736436210 小时前
华为云存储实验
网络·mysql·华为云
迷枫71210 小时前
DM8 目录结构与常用排查入口梳理
服务器·数据库
Mr.Daozhi11 小时前
RAG 进阶实战:跑通 Demo 后我连续翻了 6 次车,逐一修复才真正可用(含 Gradio Web 版)
前端·数据库·langchain·大模型·gradio·rag·科研工具