Mysql事务是如何实现的
原子性 (Atomicity) 的实现:Undo Log
原子性要求一个事务中的所有操作,要么全部成功执行,要么全部失败回滚。InnoDB使用Undo Log(撤销日志)来保证这一点。
- 工作原理:当一个事务需要对数据进行修改时,InnoDB会首先将数据的旧版本(修改前的数据)记录到Undo Log中。这个日志记录的是逻辑上的“反向操作”。
- 实现回滚:如果事务因为任何原因需要回滚(比如用户执行
ROLLBACK,或者发生错误),InnoDB就会找到该事务对应的Undo Log,并按照相反的顺序执行其中的操作,从而将数据恢复到事务开始前的初始状态。 - 实现原子性:即使在事务执行过程中数据库发生崩溃,重启后InnoDB依然可以通过Undo Log来回滚那些已经执行但尚未提交的事务,确保了“要么全做,要么全不做”的原子性。
隔离性 (Isolation) 的实现:MVCC 与锁
隔离性要求并发执行的事务之间互不干扰,看起来就像是串行执行一样。InnoDB主要通过MVCC(多版本并发控制)和锁机制来实现隔离性。
-
MVCC (Multi-Version Concurrency Control): 这是实现读-写并发的关键,主要用于处理“快照读”(普通的
SELECT)。它通过我们之前讨论过的Undo Log版本链和ReadView(读视图)机制,为每个读事务提供一个一致性的数据快照。这样,读操作就不需要等待写操作释放锁,而是可以直接读取数据的历史版本,极大地提升了并发性能。不同隔离级别(如读已提交、可重复读)的差异,主要就体现在ReadView的创建时机上。 -
锁 (Locking): 当MVCC无法解决冲突时(主要是写-写冲突),InnoDB就会使用锁机制。这主要用于处理“当前读”(如
SELECT...FOR UPDATE,UPDATE,DELETE)。当一个事务需要修改数据时,它会先获取该数据的排他锁(X锁),阻止其他事务对该数据进行任何修改,直到当前事务提交或回滚释放该锁。通过锁,InnoDB保证了在任何时刻,最多只有一个事务能修改同一份数据。
持久性 (Durability) 的实现:Redo Log 与 WAL
持久性要求一旦事务提交,其对数据库的修改就是永久性的,即使发生系统崩溃也不会丢失。InnoDB使用Redo Log(重做日志)和WAL(Write-Ahead Logging,预写日志)技术来高效地实现持久性。
- WAL技术:当数据需要修改时,InnoDB会先修改内存中的数据页(在Buffer Pool里),然后将这次修改的物理操作记录到Redo Log中。事务提交时,并不需要立即将修改过的数据页刷回磁盘(这是一个慢速的随机IO),而只需要保证对应的Redo Log已经刷入磁盘(这是一个快速的顺序IO)。
- 实现持久性:只要Redo Log成功写入磁盘,事务的提交就被认为是完成了。如果此时数据库宕机,内存中的数据修改虽然丢失了,但重启后InnoDB可以通过重放磁盘上的Redo Log,将所有已提交事务的修改重新应用到数据页上,从而恢复到宕机前的状态,保证了数据的持久性。
一致性 (Consistency) 的实现:多方协同的结果
一致性是事务追求的最终目标,它要求数据库从一个一致性状态转变到另一个一致性状态。它不是由单一技术实现的,而是由原子性、隔离性和持久性共同保障的结果。
- 原子性保证了事务的完整执行或完全不执行,防止了因部分操作失败而导致的数据不一致。
- 隔离性保证了并发事务之间不会产生异常的中间状态,使得每个事务都感觉自己是在一个独立的环境中运行。
- 持久性保证了已提交的事务结果不会因系统故障而丢失,维护了数据状态的稳定。
此外,数据库本身定义的约束(如主键、外键、唯一性约束等)也是保证一致性的重要部分。
一个事务的完整生命周期
我们可以通过一个UPDATE事务的生命周期来串联起这些机制:
1. 事务开始。
2. 执行UPDATE语句:
* InnoDB首先需要执行一个“当前读”,获取这行数据的排他锁。
* 将这行数据的原始值写入Undo Log。
* 在内存的Buffer Pool中修改这行数据。
* 将这个修改操作的物理变更记录到Redo Log Buffer中。
3. 执行COMMIT:
* 这是一个“两阶段提交”过程,为了协调Redo Log和Binlog的一致性。
* 第一阶段:Redo Log进入prepare状态,并刷入磁盘。
* 第二阶段:如果开启了Binlog,则将Binlog写入磁盘。
* 第三阶段:Redo Log进入commit状态。
* 一旦Redo Log commit完成,事务就被认为是成功提交并持久化了。
4. 后台线程会在后续某个合适的时机,将Buffer Pool中被修改过的数据页(脏页)异步地刷回到磁盘文件中。
总结来说,MySQL的事务实现是一个精妙的协同系统:Undo Log负责回滚和原子性,Redo Log负责持久性和崩溃恢复,MVCC和锁共同负责隔离性,而这一切都是为了达成最终的一致性目标。