事务操作
ACID 特性
| 特性 | 说明 | 实现机制 |
|---|---|---|
| 原子性 | 事务不可分割,要么全成功要么全失败 | undo log |
| 一致性 | 事务前后数据状态一致 | 其他三个特性保证 |
| 隔离性 | 事务之间互不干扰 | MVCC + 锁 |
| 持久性 | 事务提交后数据永久保存 | redo log |
并发问题
| 问题 | 描述 |
|---|---|
| 脏读 | 读到其他事务未提交的数据 |
| 不可重复读 | 同一事务内两次读取同一行数据不一致 |
| 幻读 | 同一事务内两次读取记录数不一致 |
脏读
不可重复读
幻读
隔离级别
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 性能 |
|---|---|---|---|---|
| Read Uncommitted | ✅ | ✅ | ✅ | 最高 |
| Read Committed | ❌ | ✅ | ✅ | 较高 |
| Repeatable Read | ❌ | ❌ | ✅ | 一般 |
| Serializable | ❌ | ❌ | ❌ | 最低 |
MVCC
MVCC(Multi-Version Concurrency Control)多版本并发控制,用于实现 RC 和 RR 隔离级别。核心组件
| 组件 | 说明 |
|---|---|
| 隐藏字段 | DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID |
| undo log | 记录数据的历史版本 |
| Read View | 判断版本可见性 |
隐藏字段
每行数据都有三个隐藏字段:| 字段 | 说明 |
|---|---|
| DB_TRX_ID | 最后修改该行的事务 ID |
| DB_ROLL_PTR | 指向 undo log 的指针 |
| DB_ROW_ID | 隐藏主键(无主键时使用) |
版本链
Read View
Read View 记录当前活跃事务,用于判断版本可见性。| 字段 | 说明 |
|---|---|
| m_ids | 活跃事务 ID 列表 |
| min_trx_id | 最小活跃事务 ID |
| max_trx_id | 下一个待分配的事务 ID |
| creator_trx_id | 创建该 Read View 的事务 ID |
RC vs RR 的区别
| 隔离级别 | Read View 生成时机 |
|---|---|
| RC | 每次 SELECT 都生成 |
| RR | 第一次 SELECT 时生成 |
- RC:每次读都是最新视图,能读到其他事务已提交的数据
- RR:使用同一个视图,看不到后续提交的数据
日志
redo log(重做日志)
- 作用:保证事务持久性
- 原理:记录数据页的物理变化
- 机制:WAL(Write-Ahead Logging),先写日志再写磁盘
undo log(回滚日志)
- 作用:保证事务原子性,支持 MVCC
- 原理:记录数据修改前的值
- 用途:
- 事务回滚
- MVCC 版本链
binlog(归档日志)
- 作用:主从复制、数据恢复
- 位置:Server 层
- 格式:
- STATEMENT:记录 SQL 语句
- ROW:记录行数据变化
- MIXED:混合模式
两阶段提交
确保 redo log 和 binlog 一致:事务常见问题
Q1: 大事务的危害?
- 锁定资源时间长,影响并发
- undo log 膨胀
- 主从延迟
Q2: 如何避免长事务?
- 控制事务大小
- 避免在事务中做耗时操作
- 设置超时时间
Q3: RR 级别下如何解决幻读?
- 快照读:MVCC
- 当前读:间隙锁(Next-Key Lock)