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

相关推荐
xmjd msup18 分钟前
mysql的分区表
数据库·mysql
Lyyaoo.18 分钟前
【JAVA Spring面经】Spring 事务失效情况
java·数据库·spring
MeAT ITEM23 分钟前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
dovens27 分钟前
PostgreSQL 中进行数据导入和导出
大数据·数据库·postgresql
IOT.FIVE.NO.127 分钟前
claude code desktop cowork报错解决和记录Workspace..The isolated Linux environment ...
linux·服务器·数据库
Rick199336 分钟前
mysql 慢查询怎么快速定位
android·数据库·mysql
科技小花8 小时前
全球化深水区,数据治理成为企业出海 “核心竞争力”
大数据·数据库·人工智能·数据治理·数据中台·全球化
X56619 小时前
如何在 Laravel 中正确保存嵌套动态表单数据(主服务与子服务)
jvm·数据库·python
虹科网络安全10 小时前
艾体宝干货|数据复制详解:类型、原理与适用场景
java·开发语言·数据库
2301_7717172110 小时前
解决mysql报错:1406, Data too long for column
android·数据库·mysql