日志
慢查询日志 slow query log
重做日志 redo log
redo log 是 InnoDB 引擎特有的日志。
WAL 技术 write-ahead logging
核心是:先写日志,再写磁盘。
当有一条记录需要更新,InnoDB 引擎会先把记录写到 redo log 里面,并更新内存,这个时候就算更新完成了。同时,InnoDB 引擎会在系统空闲的时候, 将这个操作记录更新到磁盘里面。
redo log 使用 write pos 来标记当前记录的位置,checkpoint 标记当前要擦除的位置。
归档日志 binlog
binlog 与 redo log 的区别?
- binlog 是 server 层日志,所有引擎都可以使用。
- redo log 是物理日志,记录的是“在某个数据页上做了什么修改”; binlog 是逻辑日志,记录的是这个语句的原始逻辑。
- redo log 是循环写的,空间固定会用完; binlog 是可以追加写入的。“追加写” 是指 binlog 文件写入一定大小后会切换到下一个,并不会覆盖 以前的日志。
两阶段提交
- prepare
- commit
- 事务的修改首先被记录到 redo log 中,并标记为 prepare 状态。此时,事务没有提交,redo log 保证了即使系统崩溃,更改也不会丢失。
- 一旦 redo log 成功记录,事务的修改就会被记录到 binlog 中。完成这一步后,事务在 redo log 中标记为已提交(commit)。
为什么要有 “两阶段提交” 呢?
- 保证数据的一致性
- 确保复制的准确性
- 事务的原子性和持久性
回滚日志 undo log
InnoDB 中,为了回滚而记录的东西成为 undo log。
undo log 分为三种
- insert undo log
- update undo log
- delete undo log
- 删除操作只是设置一下老记录中 DELETE_BIT 的隐式字段,并不是真正的将过时的记录删除。
- 为了节省磁盘空间,InnoDB 由专门的 purge 线程来清理 DELETE_BIT 为 true 的记录。
- purge 维护了自己的 read view, 如果某个记录的 DELETE_BIT 为 true,且 DB_TRX_ID 相对于 purge 线程的 read view 可见,那么这条记录 一定可以被安全清除的。
SQL 执行时添加 undo log 的过程
- 事务 A 向 person 表中插入了一条记录
name | age | DB_ROW_ID(隐式主键) | DB_TRX_ID(最后一次修改的事务ID) | DB_ROLL_PTR(回滚指针) |
---|---|---|---|---|
Jerry | 24 | 1 | null | null |
- 事务 B 将 name 改为 Tom
- 在事务 B 修改该行记录时,数据库会先对该行加排他锁
- 然后把该行数据拷贝到 undo log 中,作为旧纪录
- 拷贝完毕之后,修改该行记录为 Tom,并且修改隐藏字段的事务 ID 为当前事务 B 的ID,回滚指针指向拷贝到 undo log 的副本记录,表示我的上一个版本就是它。
- 事务提交之后,释放锁。
事务 B
name | age | DB_ROW_ID(隐式主键) | DB_TRX_ID(最后一次修改的事务ID) | DB_ROLL_PTR(回滚指针) |
---|---|---|---|---|
Tom | 24 | 1 | 1 | ox11223344 |
undo 日志
name | age | DB_ROW_ID(隐式主键) | DB_TRX_ID(最后一次修改的事务ID) | DB_ROLL_PTR(回滚指针) |
---|---|---|---|---|
Jerry | 24 | 1 | null | null |
- 事务 C 将 age 修改为 30
- 在事务 C 修改该记录时,数据库对该数据加锁
- 将数据拷贝到 undo log,此时发现 undo log 中有这条记录,那么最新的旧数据作为链表的表头,插在 undo log 中的该行记录最前面。
- 修改 age 为 30,并且修改 DB_TRX_ID、DB_ROLL_PTR 字段
- 事务提交,释放锁
事务 C
name | age | DB_ROW_ID(隐式主键) | DB_TRX_ID(最后一次修改的事务ID) | DB_ROLL_PTR(回滚指针) |
---|---|---|---|---|
Tom | 30 | 1 | 1 | ox12341234 |
undo 日志
name | age | DB_ROW_ID(隐式主键) | DB_TRX_ID(最后一次修改的事务ID) | DB_ROLL_PTR(回滚指针) |
---|---|---|---|---|
Tom | 24 | 1 | 1 | ox11223344 |
Jerry | 24 | 1 | null | null |
总结
事务对同一记录的修改,会导致该记录的 undo log 成为一条记录版本线性表(链表), undo log 的链首就是最新的旧记录,链尾就是最早的旧记录。