InnoDB工作原理

本文针对InnoDB进行深入理解(学习向)

一、架构:

下面图祖传的了,我截自【MySQL | 进阶篇】08、InnoDB 引擎架构、事务原理及 MVCC 讲解_事务、索引、mvcc机制-优快云博客

 解释一下:

由2部分组成

1、内存

        Buffer Pool(缓冲池)​: 缓存表数据和索引,减少磁盘 I/O。

        组成:数据页+索引页+change buffer二级索引缓存+ Adaptive Hash Index 自适应哈希索引

                change buffer是针对二级索引的更改(有更改先写到buffer中,)

2、磁盘

  • 系统表空间
  • 独立表空间
  • 通用表空间
  • 临时表空间

架构看起来很复杂,可以先往下看,你现在只需要知道:

InnoDB一端受数据库服务层控制,先操作Buffer Pool缓冲池,再用缓冲池与磁盘做交互

Buffer Pool缓冲池是个桥梁,非常关键!

 二、工作原理:

2.1 读数据

流程是:

1. 先查找Adaptive Hash来判断要查询的页是否在Buffer Pool(缓存加载是按页为单位,而不是行)

2. 如果没命中,从磁盘加载该页到Buffer Pool。更新LRU链表(记录页的访问热度,优先保留高频访问的页。低频的会在空间不足时先淘汰)

2.2 写数据

流程稍复杂一点:

1. 加锁(先不展开讲)

2. 写undo log

写入内容是:

  • update:记录修改前的完整行数据。
  • delete:记录被删除的行数据。
  • insert:记录新行的主键(用于回滚时删除)。

 undo log就是一个备份作用,为了后续的回滚

至于undo log文件位置,数据库Data文件夹下的undo_001和undo_002(默认2个,可以改)

undo log是所有库公用的文件因为事务可以跨库,所以undo log也需要跨库

3. 写入buffer pool,写后的页标为“脏页”

若修改的是 ​​非唯一索引​​,先写入 Change Buffer(减少随机 I/O)

4. 写redo log

写入内容类似于:“页号X,偏移量Y处写入数据Z”

 与undo log的位置一样

4.5 异步刷盘:

刷盘就是把redo log的数据写入磁盘,有两种刷盘策略

innodb_flush_log_at_trx_commit =0    每秒定时刷盘   性能最高,最不安全!

innodb_flush_log_at_trx_commit =1    事务提交即刷盘  性能最低,最安全

innodb_flush_log_at_trx_commit =2    事务提交写入page cache

page cache你可能不熟悉, 下图来自JavaGuideMySQL三大日志(binlog、redo log和undo log)详解 | JavaGuide 描述page cache,InnoDB有额外线程定时用page cache刷盘,如果innodb_flush_log_at_trx_commit =2,那么page cache刷盘频率会更高

5.  事务提交:

两阶段提交:

 Binlog是服务层的日志,事务提交时一并写入,与引擎无关

Redolog是引擎层日志,事务执行时持续写入,仅InnoDB有

 两阶段提交是为了保证 Binlog、Redolog和数据库内容三者一致

Binlog的作用是:保证了 MySQL 集群架构的数据一致性。

redolog的作用是:让 InnoDB 存储引擎拥有了崩溃恢复能力。

二者配合起来才能保证数据库的高可用

三、脏读、不可重复读、幻读:

很多人知道脏读、不可重复读、幻读,但是不很理解底层是怎么样的情况,下边结合InnoDB的架构来分析下:

3.1 脏读

常规解释:

事务A在写数据,事务B读取了事务A还没提交的数据,若事务A最终回滚,事务B读到的就是无效的“脏数据”。

底层:

  1. ​Buffer Pool 的脏页​

    • 事务A修改数据时,先在 Buffer Pool 中生成​​脏页​​(内存中修改但未刷盘)。
    • 事务B直接从 Buffer Pool 读取该脏页(​​读未提交隔离级别下不检查事务状态​​)。
  2. ​Undo Log 未生效​

    • 事务A的修改尚未提交,对应的 Undo Log 仍处于活跃状态(未释放)。
    • 事务B直接读Buffer Pool数据。(读未提交(Read Uncommitted)隔离级别会​​忽略 MVCC 版本链​​)
  3. ​A回滚,B读到的数据失效

    若事务A回滚,会通过 Undo Log 恢复数据,导致事务B之前读到的数据失效。

3.2 不可重复读

常规解释:

事务A内多次读取同一数据,期间事务B修改并提交了该数据,导致事务A前后读取结果不一致。

底层:

  1. ​MVCC 的 ReadView 生成时机​

    • 在读已提交(Read Committed)隔离级别下,​​每次查询都会生成新的 ReadView​​。
    • 事务B提交后,事务A的新 ReadView 会看到事务B的修改(即使事务A未结束)。
  2. ​Undo Log 版本链的可见性​

    • 事务A首次读取时,从 Undo Log 链中找到可见版本(假设为版本V1)。
    • 事务B提交后,Undo Log 链新增版本V2(已提交),事务A的新查询会跳过V1读取V2。

 

3.3 幻读

常规解释:

事务A内多次执行相同查询,期间事务B插入或删除了符合查询条件的行,导致事务A两次查询的数据行数不一致

底层:

  1. MVCC 的快照读 vs 当前读​

    • ​快照读​​(普通SELECT):基于首次 ReadView,看不到其他事务插入的数据。
    • ​当前读​​(SELECT FOR UPDATE):会看到最新提交的数据,导致幻读。
  2. ​间隙锁(Gap Lock)的缺失​

    • 在可重复读(Repeatable Read)隔离级别下:
      • 若事务A未显式加锁(如 FOR UPDATE),事务B可插入符合条件的新行。
      • 事务A的当前读会看到这些新行(幻读)。
  3. ​临键锁(Next-Key Lock)的解决方案​

    • InnoDB 默认在 RR 隔离级别下对范围查询加临键锁(记录锁 + 间隙锁),阻止其他事务插入。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值