找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1186

积分

0

好友

210

主题
发表于 3 天前 | 查看: 6| 回复: 0

一、事务与ACID特性回顾

事务是数据库中进行一系列操作的逻辑单元,这些操作要么全部成功,要么全部失败。其核心特性被称为ACID。

  1. 原子性
    事务被视为一个不可分割的原子操作,要么全部完成,要么回滚到执行前的状态。
  2. 一致性
    事务执行前后,数据库都处于一致的状态,不会违反任何数据完整性约束。
  3. 隔离性
    多个并发事务的执行互不干扰,数据库提供了不同的隔离级别来控制这种干扰的程度。
  4. 持久性
    一旦事务提交,其所作的修改就会永久地保存在数据库中。

二、InnoDB事务实现的核心组件概览

MySQL数据库/中间件生态中,InnoDB存储引擎通过一套精密的机制实现ACID:

  • Redo Log:保障持久性
  • Undo Log:保障原子性,并为MVCC提供基础。
  • 锁机制:实现隔离性的一部分。
  • MVCC:实现隔离性的另一部分,支持非阻塞读。
  • 两阶段提交:协调Redo Log与Binlog,确保数据一致性。

整体思想遵循 WAL:先写日志,后写数据,通过日志、版本控制和锁来协同保障事务的ACID特性。

三、原子性的基石:Undo Log

原子性要求事务可以回滚,这依赖于 Undo Log

1. Undo Log的作用

它记录了如何将数据恢复到旧版本。例如执行UPDATE时,会记录被修改字段的原始值。

主要承担两个职责:

  • 事务回滚:当执行ROLLBACK时,InnoDB会根据Undo Log进行逆向操作。
  • 构建MVCC版本链:每一行数据的修改历史通过Undo Log串联起来,形成版本链,使得其他事务可以进行“快照读”。

2. Undo Log的类型

  • Insert Undo Log:记录INSERT操作,仅在事务回滚时需要,提交后可快速清理。
  • Update Undo Log:记录UPDATEDELETE操作,除用于回滚外,还可能被其他事务的MVCC读取,因此清理时机由系统根据活跃事务情况决定。

四、持久性的保障:Redo Log与WAL

为了避免频繁、缓慢的随机磁盘IO,InnoDB采用 WAL 机制:Write-Ahead Logging

1. 核心流程

  1. 事务修改数据时,首先在内存的Buffer Pool中操作,生成脏页。
  2. 同时,将这次物理修改(如表空间号、页号、具体修改内容)记录到 Redo Log Buffer
  3. 事务提交时,根据策略(如innodb_flush_log_at_trx_commit),保证相关的Redo Log至少被刷新到磁盘。
  4. 内存中的脏页则由后台线程在适当时机异步刷回磁盘。

只要Redo Log成功落盘,即使此时数据页未刷盘,宕机后也能通过重放Redo Log恢复数据,从而保证了持久性。

2. 崩溃恢复

MySQL重启时,会扫描Redo Log,从最后一个检查点开始,重新应用所有已提交但数据未落盘的事务修改。

五、隔离性的实现:锁与MVCC

隔离性通过 MVCC 协同实现。

1. 锁机制

锁主要用于处理写-写冲突,确保并发的修改操作有序进行。InnoDB的行级锁主要包括:

  • 记录锁:锁定单条记录。
  • 间隙锁:锁定记录之间的间隙,防止插入。
  • 临键锁:记录锁与间隙锁的组合,是InnoDB在默认隔离级别下防止幻读的主要手段。
  • 意向锁:表级锁,用于快速判断表中是否存在行锁。

2. MVCC机制

MVCC使得普通的SELECT读操作可以不加锁,通过读取历史版本来实现非阻塞读,极大提升了并发性能。
InnoDB每行记录包含两个隐藏字段:

  • trx_id:最后一次修改该行的事务ID。
  • roll_pointer:指向该行上一个版本的Undo Log记录指针。

不同的事务根据其启动时机和隔离级别,会基于Undo Log构成的版本链,决定读取哪个版本的数据。

六、四种隔离级别的具体实现

MySQL支持四种隔离级别,其实现差异主要体现在MVCC和锁的使用上。

  1. 读未提交
    直接读取数据页上的最新值,基本不使用MVCC,存在脏读问题。

  2. 读已提交
    每次执行SELECT时都会生成一个独立的“读视图”。因此,在同一事务内,两次相同的查询可能读到不同的数据(不可重复读)。

  3. 可重复读
    在事务开始时生成一个“读视图”,并在整个事务周期内使用它,从而保证多次读取的一致性。对于快照读,通过MVCC避免幻读;对于当前读,则通过临键锁来防止其他事务插入新数据。这是InnoDB的默认隔离级别。

  4. 串行化
    所有读操作都会加锁,相当于强制事务串行执行,隔离级别最高,但并发性能最差。

七、一致性的达成

一致性是事务追求的最终目标,它是原子性、隔离性、持久性共同作用下的结果,同时也依赖于:

  • 数据库本身定义的约束(主键、外键、唯一键等)。
  • 应用程序正确的业务逻辑。

八、关键协作:Redo与Binlog的两阶段提交

为了保证存储引擎层(Redo Log)和Server层(Binlog)在崩溃恢复和主从复制时的一致性,InnoDB采用两阶段提交

  1. Prepare阶段:InnoDB将事务的Redo Log写入磁盘,并标记状态为prepare
  2. Commit阶段:写入Binlog,随后将Redo Log的状态修改为commit

崩溃恢复时,如果发现Redo Log处于prepare状态,则会检查对应的Binlog是否完整。如果完整,则提交事务;否则,回滚事务。

九、锁的释放与死锁

InnoDB的加锁遵循两阶段锁协议:在事务执行过程中逐步获取锁,在事务提交或回滚时统一释放所有锁。
这种机制可能引发死锁。InnoDB有后台的死锁检测机制,一旦发现死锁,会选择回滚代价最小的事务来打破僵局。

十、崩溃恢复流程简述

数据库意外宕机后重启,恢复流程保证了ACID:

  1. 重放Redo Log,将所有已提交事务的修改重新应用到数据页上(重做)。
  2. 通过Undo Log,回滚所有未提交事务的修改(回滚)。
    最终,数据库恢复到一致性状态:已提交的事务全部生效,未提交的事务如同从未发生。

十一、总结:InnoDB事务实现的整体脉络

理解InnoDB事务的实现,可以构建如下知识框架:

  • 持久性靠Redo:WAL机制确保先写日志,数据可恢复。
  • 原子性靠Undo:记录旧值,支持回滚与版本链。
  • 隔离性靠MVCC+锁:读写分离,MVCC实现无锁快照读,锁控制并发写。
  • 一致性靠协作:上述机制与数据库约束、后端与架构层的正确逻辑共同作用。
  • 协调靠2PC:两阶段提交确保Redo与Binlog的最终一致,这是保障网络与系统数据可靠性的关键技术点。

掌握这些核心原理,有助于在开发中更精准地使用事务、诊断并发问题并优化数据库性能。




上一篇:多模态大模型Prompt调优实战:如何突破四大计算瓶颈?
下一篇:SpringBoot+Vue构建海南自贸港一站式智慧服务平台
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-17 18:07 , Processed in 0.109368 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表