2026/2/8 9:15:30
网站建设
项目流程
在网站建设上的发言总结,自己做网站代码,峡江网站建设,网站设计和制作费用以UPDATE test SET a1 WHERE id2为例#xff0c;完整讲解执行流程。一、核心概念速记在开始之前#xff0c;你需要记住三个日志文件的作用#xff1a;undo log#xff1a;用于事务回滚#xff0c;记录数据修改前的旧值redo log#xff1a;用于崩溃恢复#xff0c;记录数…以UPDATE test SET a1 WHERE id2为例完整讲解执行流程。一、核心概念速记在开始之前你需要记住三个日志文件的作用undo log用于事务回滚记录数据修改前的旧值redo log用于崩溃恢复记录数据修改后的新值binlog用于主从复制和数据恢复记录所有数据变更二、执行步骤详解第一步记录undo log事务准备阶段事务开始时MySQL会先记录undo log。操作UPDATE test SET a1 WHERE id2 undo log记录 ┌─────────────────────┐ │ 操作类型UPDATE │ │ 表名test │ │ id 2的旧值a0 │假设原来a的值是0 └─────────────────────┘为什么需要undo log如果你执行了UPDATE然后想回滚ROLLBACKMySQL就用undo log里的旧值把数据改回去。BEGIN; UPDATE test SET a1 WHERE id2; -- undo log记录 a原来是0 ROLLBACK; -- 用undo log把a改回0第二步写redo logprepare阶段undo log记录完后存储引擎InnoDB会写入redo log并标记状态为prepare。redo log内容 ┌──────────────────────────────────┐ │ 操作类型UPDATE │ │ id2, a1新值 │ │ 状态prepare准备中 │ └──────────────────────────────────┘ ↓ (立即刷入磁盘) 磁盘中的redo log file这一步的意义保证即使系统崩溃通过redo log也能恢复数据只有写到磁盘的redo log才真正安全状态是prepare说明还没有最终提交第三步获取行锁并修改数据执行阶段写完redo log后MySQL获取行锁在内存中修改数据。步骤流程 1. 获取id2这一行的行锁 ↓ 2. 从磁盘读入内存buffer pool - 读到id2, a0旧值 ↓ 3. 在内存中修改 - 改为id2, a1新值 ↓ 4. 标记为脏页dirty page - 说明这个数据页的内存版本和磁盘版本不一致注意此时数据还在内存中没有写入磁盘这是InnoDB的优化策略立即写磁盘很慢每次都做磁盘IO先在内存中修改标记为脏页后台有线程在适当时机将脏页刷入磁盘第四步写入binlog服务层记录binlog是MySQL服务层维护的日志不是存储引擎的。在事务提交前MySQL会将操作写入binlog。binlog内容 ┌──────────────────────────────────┐ │ UPDATE test SET a1 WHERE id2 │ │ 时间戳2025-01-07 10:30:00 │ │ 连接ID12345 │ └──────────────────────────────────┘ binlog主要用途 1. 主从复制从库读主库的binlog来同步数据 2. 数据恢复结合备份文件恢复到某个时间点第五步提交事务commit阶段这是关键的一步包含两个操作操作1修改redo log状态为commitredo log状态变化 prepare → commit redo log ┌──────────────────────────────────┐ │ 操作类型UPDATE │ │ id2, a1 │ │ 状态commit已提交 │ └──────────────────────────────────┘ 立即刷入磁盘操作2释放行锁操作完成释放id2这一行的锁 其他事务现在可以修改id2的数据了三、两阶段提交Two-Phase Commit这是确保redo log和binlog一致性的机制也是为什么MySQL的可靠性这么高的原因。第一阶段Prepare ↓ redo log写入磁盘状态prepare ↓ 不能立即提交要等binlog写完 第二阶段Commit ↓ binlog写入磁盘 ↓ redo log状态改为commit写入磁盘 ↓ 事务最终完成为什么要这样设计假设没有两阶段提交场景1只写redo log不写binlogUPDATE执行了 → 主库数据改了 → 从库没收到 →主从数据不一致场景2只写binlog不写redo logUPDATE执行了 → binlog记录了 →系统崩溃 → 无法恢复数据两阶段提交保证要么redo log和binlog都成功数据最终一致要么都失败系统可以恢复到之前的状态四、崩溃恢复场景如果在commit阶段崩溃了怎么办假设redo log已经写入preparebinlog已经写入 但redo log的commit状态还没写入磁盘就崩溃了 MySQL重启后 1. 扫描redo log 2. 看到这个操作状态是prepare 3. 查看binlog中是否有对应的操作记录 4. 如果binlog中有说明操作已经完成就把redo log改为commit 5. 如果binlog中没有说明操作没完成就回滚这个操作五、完整时间线总结UPDATE test SET a1 WHERE id2 执行过程 时间点1事务开始 → 记录undo logid2, a原来的值 时间点2执行阶段 → 写redo logprepare状态 → 获取行锁 → 在buffer pool中修改数据为a1 → 标记为脏页 时间点3提交阶段开始 → 写binlog用于主从复制 时间点4提交阶段完成 → 修改redo log状态为commit → 释放行锁 → 事务完成 时间点5后台线程不一定立即 → 将脏页刷入磁盘 → 如果故障恢复需要redo log可以帮忙恢复六、需要理解为什么INSERT/UPDATE/DELETE很慢因为要做这么多事写undo log、写redo log、写binlog、获取锁、修改数据、提交事务所以批量操作用batch比逐条执行快得多为什么MySQL这么可靠多层日志保护undo log、redo log、binlog两阶段提交确保数据一致性即使系统崩溃也能恢复主从复制为什么会延迟因为从库是从主库的binlog读取数据主库写完数据后从库需要网络传输、解析、执行这之间有延迟数据库性能优化的角度redo log的大小和io_capacity参数很重要批量操作时用事务分组减少提交次数避免频繁的小事务