MySQL基本概念


第一部分:存储引擎与索引结构

1.1 什么是存储引擎?

MySQL 支持多种存储引擎 (Storage Engine),负责数据的存储、检索和事务管理。

最常用的是 InnoDB(默认,支持事务、行锁、外键)和 MyISAM(不支持事务,表锁)。

生产环境几乎全部使用 InnoDB


1.2 InnoDB 的数据组织:B+ 树

🔍 为什么用 B+ 树?
  • 磁盘 I/O 是性能瓶颈 → 需要减少磁盘读取次数
  • B+ 树是多路平衡搜索树,高度低(通常 3~4 层),一次查询只需 3~4 次磁盘 I/O
🌲 B+ 树 vs B 树
特性 B 树 B+ 树(InnoDB 使用)
数据存储位置 内部节点 + 叶子节点 仅叶子节点存数据
叶子节点连接 双向链表连接(利于范围查询)
查询效率 稳定 更稳定 + 范围扫描快
📂 InnoDB 的两类 B+ 树索引
类型 说明 特点
聚簇索引(Clustered Index) 主键索引,叶子节点存整行数据 表数据按主键物理排序
二级索引(Secondary Index) 普通索引,叶子节点存主键值 查非主键字段需"回表"

💡 例:SELECT name FROM users WHERE id = 100;

  • id 是主键 → 走聚簇索引,1 次 I/O
  • 若查 email = 'a@b.com',而 email 有二级索引 → 先查二级索引得 id,再回表查聚簇索引 → 2 次 I/O

第二部分:事务与 ACID

2.1 什么是事务(Transaction)?

事务是一组数据库操作,要么全部成功,要么全部失败,是一个不可分割的工作单元。

sql 复制代码
BEGIN;
UPDATE account SET balance = balance - 100 WHERE user = 'A';
UPDATE account SET balance = balance + 100 WHERE user = 'B';
COMMIT; -- 或 ROLLBACK

2.2 ACID 四大特性

特性 含义 MySQL 如何实现
Atomicity(原子性) 事务不可分割 Undo Log(回滚日志)
Consistency(一致性) 事务前后数据合法(如余额 ≥0) 应用逻辑 + 约束(唯一索引等)
Isolation(隔离性) 并发事务互不干扰 MVCC + 锁机制
Durability(持久性) 提交后数据永久保存 Redo Log + innodb_flush_log_at_trx_commit=1

2.3 隔离级别与并发问题

隔离级别 脏读 不可重复读 幻读 MySQL 默认
Read Uncommitted
Read Committed (Oracle 默认)
Repeatable Read ⚠️(基本解决) InnoDB 默认
Serializable 性能差

🔍 InnoDB 在 RR 级别通过 MVCC + Next-Key Lock 解决幻读

三大并发问题:
  • 脏读:读到未提交的数据
  • 不可重复读:同一事务中多次读,结果不同(行被 update)
  • 幻读:同一事务中多次查,行数不同(有新行 insert)

第三部分:日志系统 ------ 崩溃恢复的核心

InnoDB 通过 WAL(Write-Ahead Logging) 机制保证性能与安全:

3.1 Redo Log(重做日志)

  • 作用 :崩溃恢复时重放已提交事务
  • 特点
    • 物理日志(记录"页修改")
    • 循环写入(固定大小,如 4GB)
    • 先写 Redo Log,再改内存数据页

💡 innodb_flush_log_at_trx_commit = 1 控制 Redo Log 刷盘时机

3.2 Undo Log(回滚日志)

  • 作用
    • 事务回滚
    • MVCC(多版本并发控制)提供历史快照
  • 存储:在共享表空间或独立 undo 表空间

3.3 Binlog(二进制日志)

  • 作用
    • 主从复制
    • 基于时间点的数据恢复
  • 格式
    • STATEMENT:记录 SQL(可能不一致)
    • ROW:记录每行变更(推荐
    • MIXED:混合

💡 sync_binlog = 1 控制 Binlog 刷盘时机


第四部分:主从复制原理

4.1 复制流程(异步)

Slave_DB Slave_SQL_Thread Relay_Log Slave_IO_Thread Master Slave_DB Slave_SQL_Thread Relay_Log Slave_IO_Thread Master 1. 写 Binlog 2. Slave 连接,请求 Binlog 3. 写 Relay Log 4. 重放 Relay Log

4.2 GTID(全局事务 ID)

  • 格式:server_uuid:transaction_id
  • 优势:自动定位复制位点,切换主从无需找 binlog_file + position

第五部分:高可用架构(无 MGR/MHA)

5.1 架构选择:双主(Active-Standby) + 多从

  • 只允许一个主写,避免冲突
  • 备主平时 read_only = ON
  • auto_increment 奇偶分离防主键冲突

5.2 关键配置(所有节点)

ini 复制代码
# 安全底线
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1

# 强一致性基础
gtid_mode = ON
enforce_gtid_consistency = ON
binlog_format = ROW

# 防冲突
auto_increment_increment = 2
auto_increment_offset = 1  # 主库=1,备库=2

5.3 手动故障切换步骤

  1. 停止备库复制:STOP SLAVE; RESET SLAVE ALL;
  2. 解除只读:SET GLOBAL read_only = OFF;
  3. 漂移 VIP 或更新应用配置
  4. 修复原主后,作为新从库加入

第六部分:Redis 补充(缓存与加速)

6.1 Redis 核心价值

  • 缓存:减轻 MySQL 读压力
  • 原子操作INCR/DECR 实现库存扣减
  • 数据结构:List(队列)、ZSet(排行榜)

6.2 秒杀场景示例

python 复制代码
stock_key = "stock:1001"
new_stock = r.decr(stock_key)
if new_stock >= 0:
    # 创建订单
else:
    r.incr(stock_key)  # 补偿!
    raise HTTPException(429, "售罄")

INCR/DECR 是 Redis 原子命令,线程安全


第七部分:总结 ------ 生产 Checklist

类别 必做项
存储 使用 InnoDB,主键自增
索引 合理设计二级索引,避免回表
事务 用 RR 隔离级别,短事务
日志 双1配置 + ROW 格式 binlog
复制 GTID + 半同步(可选)
高可用 双主单写 + VIP + 监控
缓存 Redis 缓存热点数据,防穿透/击穿

🌟 记住
数据库不是黑盒。理解 B+ 树、事务、日志、复制原理,才能在高并发、高可用场景下做出正确决策。

非常好的问题!MVCC(Multi-Version Concurrency Control,多版本并发控制) 是现代数据库(如 MySQL InnoDB、PostgreSQL、Oracle)实现高并发读写 的核心机制。它让你在不加锁 的情况下,也能安全地进行快照读(Snapshot Read),极大提升系统吞吐量。

下面我们用 通俗语言 + 技术细节 + 示例 来彻底讲清楚 MVCC。


一、为什么需要 MVCC?

🚫 传统锁机制的问题

假设没有 MVCC,要保证事务隔离性,只能靠加锁

  • 读操作 → 加共享锁(S锁)
  • 写操作 → 加排他锁(X锁)

后果

  • 一个长事务在更新某行,其他所有读请求都会被阻塞
  • 系统并发能力极低,用户体验差。

✅ MVCC 的目标

读不阻塞写,写不阻塞读!

即使有事务在修改数据,其他事务仍能看到一致的历史版本,无需等待。


二、MVCC 的核心思想

"不是直接修改数据,而是保留多个版本,每个事务看到自己该看的版本。"

就像 Git 的分支:

  • 每次修改生成一个新 commit(新版本)
  • 不同人可以基于不同 commit 工作,互不影响

三、InnoDB 如何实现 MVCC?

InnoDB 通过以下 3 个关键技术 实现 MVCC:

1️⃣ 隐藏字段(每行记录自带)

InnoDB 在每行数据中隐式添加 3 个字段(用户不可见):

字段 说明
DB_TRX_ID 最后修改该行的事务 ID
DB_ROLL_PTR 回滚指针,指向 Undo Log 中的旧版本
DB_ROW_ID 行 ID(仅当表无主键时使用)

💡 事务 ID(trx_id)是全局递增的数字,启动时分配。


2️⃣ Undo Log(版本链)

  • 每次 UPDATE/DELETE 时,不直接覆盖原数据 ,而是:
    1. 将旧行复制到 Undo Log
    2. 新行的 DB_ROLL_PTR 指向这个旧版本
  • 多次修改形成 版本链(Version Chain)
text 复制代码
当前行 (trx_id=105)
   ↑
   | DB_ROLL_PTR
   ↓
旧版本 (trx_id=102)
   ↑
   | DB_ROLL_PTR
   ↓
更旧版本 (trx_id=100)

3️⃣ Read View(读视图)

当一个事务执行快照读 (如普通 SELECT)时,InnoDB 会创建一个 Read View ,决定"能看到哪些版本"。

Read View 包含 4 个关键信息:
成员 说明
m_ids 当前活跃事务 ID 列表(未提交的事务)
min_trx_id m_ids 中最小的事务 ID
max_trx_id 创建 Read View 时,下一个将分配的 trx_id
creator_trx_id 当前事务自己的 ID(若为读事务则为 0)

四、可见性判断规则(核心!)

给定一行数据(版本),当前事务能否看到它?按顺序判断:

  1. 如果行的 DB_TRX_ID == 当前事务 ID

    → 自己改的,可见

  2. 如果行的 DB_TRX_ID < min_trx_id

    → 该行在 Read View 创建前已提交,可见

  3. 如果行的 DB_TRX_IDmax_trx_id

    → 该行在 Read View 创建后才开启,不可见

  4. 如果 DB_TRX_ID[min_trx_id, max_trx_id) 区间内

    → 检查是否在 m_ids(活跃事务列表)中:

    • → 未提交,不可见
    • 不在 → 已提交,可见
  5. 如果不可见,就沿着 DB_ROLL_PTR 找上一个版本,重复判断

✅ 这就是"一致性非锁定读"的原理!


五、举个完整例子 🌰

场景:账户余额查询

时间 事务 A(trx_id=100) 事务 B(trx_id=101)
T1 BEGIN;
T2 SELECT balance FROM account WHERE id=1;看到 1000
T3 BEGIN;
T4 UPDATE account SET balance = 800 WHERE id=1;
T5 SELECT balance FROM account WHERE id=1;仍看到 1000!
T6 COMMIT;
T7 SELECT balance FROM account WHERE id=1;看到 800

分析:

  • T2 时,事务 A 创建 Read View:m_ids=[100], min=100, max=102
  • T5 时,事务 A 再次 SELECT:
    • 当前行 DB_TRX_ID=101(事务 B 修改的)
    • 101[100, 102) 且在 m_ids?→ 事务 B 未提交(T5 时还在运行) → 不可见
    • 沿着 Undo Log 找到旧版本:DB_TRX_ID=100 → 是自己事务 → 可见!值为 1000

✅ 事务 A 始终看到事务开始时的一致快照,不受其他未提交事务影响。


六、MVCC 与隔离级别的关系

隔离级别 是否使用 MVCC? 行为
Read Committed (RC) 每次 SELECT 都创建新 Read View → 能看到其他事务已提交的新数据
Repeatable Read (RR) 事务中第一次 SELECT 创建 Read View,后续复用 → 保证可重复读
Serializable 强制加锁,退化为串行执行

🔍 MySQL InnoDB 默认 RR 级别,正是靠 MVCC 实现"幻读基本解决"


七、MVCC 的优势与代价

✅ 优势

  • 高并发:读写不互相阻塞
  • 一致性:提供事务开始时的数据快照
  • 性能好:避免大量读锁开销

⚠️ 代价

  • 存储开销:Undo Log 占用额外空间
  • 清理延迟:旧版本不能立即删除(需等所有可能用到它的事务结束)
  • 长事务危害:会导致 Undo Log 无法 purge,磁盘爆满!
相关推荐
wregjru2 小时前
【QT】1.QT 基础入门
数据库
2301_818732062 小时前
前端一直获取不到后端的值,和数据库字段设置有关 Oracle
前端·数据库·sql·oracle
皙然2 小时前
MyBatis 执行流程源码级深度解析:从 Mapper 接口到 SQL 执行的全链路逻辑
数据库·sql·mybatis
BXCQ_xuan2 小时前
解决飞牛nas更新后挂载硬盘提示“数据库读写失败”
数据库·飞牛nas
栗子叶2 小时前
阅读MySQL实战45讲专栏总结
数据库·mysql·innodb·主从同步·数据库原理
一只鹿鹿鹿2 小时前
springboot集成工作流教程(全面集成以及源码)
大数据·运维·数据库·人工智能·web安全
Coder_Boy_2 小时前
基于SpringAI的在线考试系统-数据库设计关联关系设计
服务器·网络·数据库
李慕婉学姐2 小时前
Springboot七彩花都线上鲜花订购平台rzb8b4z2(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
码农阿豪2 小时前
时序数据爆发增长,企业如何破解存储与分析困局?
数据库·mysql·金仓