进阶-InnoDB引擎-事务
2026/7/22 16:51:05 网站建设 项目流程

一、MySQL进阶

“当两个银行账户同时转账时,你希望系统是‘要么全部成功,要么全部失败’,而不是让钱‘消失’或‘凭空多出’。”
—— 事务,是数据库的“保险丝”,也是高并发系统的“定海神针”

为什么事务如此重要?—— 一场银行转账的危机

想象一下:
用户A有 1000 元,用户B有 500 元。
执行转账操作:
A转500元给B

如果系统在中间出错:

  • A的余额减500 → 500元
  • B的余额未加500 → 仍500元
    结果:总金额从1500元变成1000元!

💡 这就是事务失败的灾难性后果
事务(Transaction)正是为了解决这个问题而诞生——确保数据操作的原子性与一致性

1. 事务

事务的四大特性:ACID的终极密码

特性含义问题InnoDB 解决方案
Atomicity(原子性)操作要么全部成功,要么全部失败部分成功导致数据不一致Undo Log:回滚到事务前状态
Consistency(一致性)事务前后数据必须符合约束约束被破坏(如余额<0)约束检查+事务回滚
Isolation(隔离性)并发事务互不影响脏读/不可重复读/幻读MVCC+锁机制
Durability(持久性)事务提交后数据永久保存服务器宕机导致数据丢失Redo Log+刷盘机制

事务隔离级别:从“混乱”到“有序”的四重境界

MySQL 提供4 种隔离级别,从低到高依次为:

📌 1. 读未提交(Read Uncommitted)
  • 允许:脏读、不可重复读、幻读
  • 场景:对数据一致性要求极低的场景(如日志统计)
  • InnoDB 行为不加锁,直接读取最新数据
📌 2. 读已提交(Read Committed)
  • 允许:不可重复读、幻读
  • 场景:大多数Web应用(如电商订单)
  • InnoDB 行为MVCC + 语句级锁,每次查询都读取最新已提交数据
📌 3. 可重复读(Repeatable Read)✅(MySQL默认)
  • 允许:幻读
  • 场景:金融、银行系统(要求每次查询结果一致)
  • InnoDB 行为MVCC + 快照读RR级别下通过Next-Key Lock避免幻读
📌 4. 串行化(Serializable)
  • 禁止:所有并发问题
  • 场景:极端严格一致性要求(如股票交易)
  • InnoDB 行为强制加锁,所有事务串行执行

锁机制:事务的“守门员”

InnoDB 采用行级锁(而非表级锁),但锁类型复杂:

📌 1. 共享锁(S Lock)
  • 作用SELECT ... FOR SHARE
  • 特点:多个事务可以同时持有
  • 场景:读取数据时加锁,防止其他事务修改
📌 2. 排他锁(X Lock)
  • 作用UPDATE/DELETE/SELECT FOR UPDATE
  • 特点:独占锁,其他事务不能加任何锁
  • 场景:修改数据时
📌 3. 意向锁(Intention Lock)
  • 作用:表明事务想加行锁(避免表锁冲突)
  • 类型
    • IS(意向共享锁):事务想加S锁
    • IX(意向排他锁):事务想加X锁

MVCC:多版本并发控制——事务的“时间机器”

MVCC(Multi-Version Concurrency Control)是 InnoDB 实现高并发的核心技术,它让事务在不加锁的情况下实现“读不阻塞写,写不阻塞读”

事务实现:InnoDB的“幕后黑手”

事务的实现依赖三大核心技术:

组件作用关键机制
Undo Log事务回滚、MVCC记录修改前的旧值(物理记录)
Redo Log事务持久化、崩溃恢复记录修改后的操作(逻辑记录)
并发控制行锁、间隙锁、意向锁
📌 Undo Log 工作流程
  1. 事务开始:记录当前状态
  2. 修改数据:生成Undo Log(如balance=1000 → 500
  3. 提交:标记为可清理
  4. 回滚:用Undo Log恢复旧值

💡Undo Log 两种类型

  • INSERT:记录插入的行
  • UPDATE:记录修改前的旧值

具体的操作:

由前面学习了解的知识可知,首先客户端在进行事务操作时,会发起请求去操作我们的mysql服务器,在mysql服务器的innodb引擎当中,分为内存结构和磁盘结构,磁盘结构里面存放了很多的一些数据文件,内存结构当中也有很大一块区域叫Buffer Pool(缓冲池),在其中缓冲了我们很多数据的一个一个页的信息,接下来当客户端发起这次事务操作,这操作中包含了多条的update和delete语句,执行的流程如是:

首先操作缓冲区,在缓冲区当中查找有没有我们所更新的这一块数据页的索引等,如果没有,此时进行等待,后台线程会把数据从磁盘中读取出来,然后再缓存在缓冲区里面,那么接下来就读取到了该数据页,接下来就可以执行相应的更新或者删除的sql逻辑。此时操作完成之后,缓冲区中的数据发生了变更,但是磁盘中并没有。那么此时该数据页被称之为“脏页”。这个脏页我们需要通过一定的时间,后台线程才能把它刷新到磁盘当中。此时内存中和磁盘中的数据就保持一致了。

问题:数据并没有实时更新,假如在输入磁盘中数据出现了错误,此时事务也已经提交了,但是在写入磁盘中出现了错误。会造成很大的损失,数据更新的持久性也没有得到保障。此时redo log 作用出现:

我们操作的增删改的操作会被记录到 redo log 日志中,随后会刷新进磁盘当中。

📌 Redo Log 工作流程
  1. 事务修改内存中的页(变脏页)
  2. 生成Redo Log(记录操作:UPDATE accounts SET balance=500
  3. 同步刷盘:确保Redo Log在磁盘(innodb_flush_log_at_trx_commit=1
  4. 异步刷脏页到磁盘

为什么需要Redo Log?
如果直接刷脏页到磁盘,I/O 开销大;
用Redo Log先写入磁盘,再异步刷脏页,大幅提升写性能

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询