本篇讨论MySQL本身如何实现事务的ACID特性
如何保证原子性?
原子性:事务内的操作要么全成功或者全失败
- undo log 在DML操作时读取buffer pool的数据页,将数据页旧版本记录到表空间中,等事务发生错误或者显式回滚时,innodb利用undo log恢复到修改前的状态,保证全部执行或者全部不执行。
- 2PC两阶段提交 2PC指的是准备阶段、提交阶段。 redolog binlog都落盘,则准备阶段OK redo log写入commit record,修改事务状态为已提交,释放事务持有的所有行锁间隙锁
为什么要两阶段提交:保证redo log binlog的原子性。 redo log用于崩溃恢复 而binlog用于主从同步
如果redolog有修改但 binlog没有那么崩溃恢复后主库更改但从库无更改。
如果binlog有修改但主库没有修改,那么从库有更新,主库没有更新。
都会造成主从数据不一致,所以必须保证两个日志的原子性,要么全落盘,要么都不落。
如何保证一致性?
一致性:从一个满足完整性规则的状态切换到另一个也满足这些规则的状态
-
约束与触发器 主键约束,保证表中不会有重复数据 检查约束,保证表中数据合法 外键约束,保证子表中的外键对应的父表一定有记录,不会存在“悬空“或孤儿”记录 触发器保证操作不会被人为因素被跳过,只要被触发一定会执行触发器内的SQL 与DML操作同处一个事务上下文,如果出错会一起回滚,提交也是一起提交,保证了修改数据强制执行一致性逻辑,避免遗漏或部分生效
-
事务: 原子性和一致性相结合,要么全部执行,要么全部回滚。不会出现半执行的不一致状态 隔离级别与MVCC 通过MVCC、行锁、间隙锁防止读写过程中出现脏读、幻读、不可重复读等问题。 2PC 确保redo log binlog安全落盘不会出现主从数据不一致的状态
如何保证隔离性?
隔离性:并发事务互不影响,执行的效果如同串行执行
MVCC机制+锁(行锁,间隙锁,临键锁)
如何保证持久性?
持久性:事务一旦提交,修改就永久保留,即使系统崩溃也不会丢失
- redo log + 刷盘机制 保证最近数据的改动持久化到日志文件中。
- innodb的崩溃恢复机制,利用redo log的write指针的最新位置来将已提交事务持久化到磁盘。
- 双写缓冲:防止极端场景导致数据页半页写入而损坏,先把脏页写入连续双写区域,再批量写入数据文件,崩溃恢复后用双写区恢复完整页。
参考
《高性能MySQL-第四版》
《极客时间-MySQL45讲》
《MySQL技术内幕-InnoDB存储引擎-第二版》