一句话导读
本文系统梳理了 MySQL 中视图、触发器、锁机制以及 InnoDB 事务与 MVCC 的底层原理,重点理解数据库在并发与事务场景下“如何保证正确性与性能”。
一、视图 / 存储过程 / 触发器概览
1. 视图(View)
视图本质是一张虚拟表:
- 只保存 SQL 查询逻辑
- 不保存真实数据
- 查询视图时,结果是动态生成的
我的理解:可以把视图视为“可复用的 SQL 查询封装”。
视图的核心作用
- 简化查询:常用复杂 SQL 封装成视图
- 权限控制:屏蔽敏感字段,只暴露需要的数据
- 数据独立性:表结构变化对上层影响更小(封装思想)
WITH CHECK OPTION
- 用于限制通过视图进行 DML 操作
- 确保插入 / 更新后的数据仍满足视图定义条件
两种检查范围:
CASCADED(默认):级联检查当前视图及其依赖视图LOCAL:只检查当前视图
注意:
包含 group by、聚合函数、distinct、join 的视图,通常不可更新(视图与基础表中行一一对应才可以更新)
2. 存储过程与存储函数(了解)
阿里开发手册明确不推荐在业务系统中使用存储过程。
原因:
- 可维护性差
- 调试困难
- 与业务代码耦合过深
但从原理上:
- 存储过程 ≈ SQL 层函数封装
- 存储函数 = 有返回值的存储过程
3. 触发器(Trigger)
触发器是表级别的自动回调机制:
- 在
INSERT / UPDATE / DELETE - 的
BEFORE或AFTER - 自动执行一段 SQL
使用 OLD / NEW 引用数据变化前后内容。
典型场景:
- 数据校验
- 日志记录
- 约束补充
二、MySQL 锁机制全景理解
1. 锁的分类(按粒度)
| 锁类型 | 作用范围 |
|---|---|
| 全局锁 | 整个数据库 |
| 表级锁 | 整张表 |
| 行级锁 | 行(本质是索引项) |
2. 全局锁
1 | flush tables with read lock; |
- 整个数据库只读
- 常用于全库逻辑备份
InnoDB 推荐使用:
1 | mysqldump --single-transaction |
在不加锁的情况下获得一致性快照。
3. 表级锁
表锁(手动)
read lock:可读不可写write lock:读写都阻塞
元数据锁(MDL)
- 系统自动加锁
- 防止 DML 与 DDL 并发冲突:表有未提交事务时,无法修改表结构
意向锁(InnoDB)
用来“告诉表锁:我表里有行锁”
- IS(意向共享锁)
- IX(意向排他锁)
目的:
避免表锁逐行检查是否存在行锁,提高效率
4. 行级锁(InnoDB 核心)
重点理解一句话:
InnoDB 的行锁,本质是加在索引上的,而不是记录本身
三种行级锁
- Record Lock:锁定单条索引记录
- Gap Lock:锁定索引间隙(防幻读)
- Next-Key Lock:Record + Gap
索引失效 = 行锁退化为表锁
三、InnoDB 存储引擎架构
1. 核心内存结构
Buffer Pool
- 缓存数据页与索引页
- Page 级别管理
- 脏页异步刷盘
Change Buffer
- 针对 非唯一二级索引
- 先缓存修改,后合并
- 减少随机 IO
Adaptive Hash Index
- InnoDB 自动生成
- 优化等值查询
- 无需人工维护
Log Buffer
- redo / undo 日志缓冲区
- 提高日志写入效率
2. 磁盘结构要点
- Redo Log:保证事务持久性
- Undo Tablespace:存放 undo log
- Doublewrite Buffer:防止部分写失败
四、事务原理:ACID 是如何实现的?
1. ACID 对应关系
| 特性 | 实现机制 |
|---|---|
| 原子性 | undo log |
| 一致性 | redo + undo |
| 隔离性 | 锁 + MVCC |
| 持久性 | redo log |
2. redo log:保证“提交不丢”
- 物理日志
- 事务提交时先写 redo log,即 WAL(Write-Ahead Logging)
redo 解决的是:
事务成功了,但数据页还没刷盘就宕机的问题
3. undo log:保证“失败可撤销”
- 逻辑日志
- 记录“相反操作”
- delete ↔ insert
- update ↔ old value
- 用于:
- rollback
- MVCC 快照读
我的理解: 物理日志是照搬,逻辑日志需要理解其语义
五、MVCC:并发读写的核心机制
1. 当前读 vs 快照读
- 当前读:加锁,读最新数据
- 快照读:不加锁,读的版本由 readview 匹配规则决定
2. 隐藏字段
InnoDB 每行都有:
DB_TRX_ID:最近修改事务 IDDB_ROLL_PTR:指向 undo log 旧版本DB_ROW_ID(无主键时)
3. 版本链 + ReadView
- 多次修改 → 形成 undo log 版本链
- ReadView 决定:
- 哪个版本对当前事务可见
不同隔离级别:
- RC:每次 select 生成 ReadView
- RR:事务第一次 select 生成一次
六、学习总结(个人理解)
今天的学习让我对 MySQL 的理解从“会用 SQL”提升到“知道数据库在底层如何保障正确性”:
- 视图本质是 SQL 封装 + 权限控制
- 锁机制复杂但核心是 粒度与索引
- InnoDB 的行锁是加在索引上的
- redo log 保证“已提交一定成功”
- undo log 保证“失败一定能回滚”
- MVCC = 隐藏字段 + undo log + ReadView
- ACID 不是概念,而是一整套工程实现