多版本并发控制
Multi-Version Concurrency Control, MVCC
地位
InnoDB存储引擎实现隔离级别的一种具体方式
- 主要用来实现Read Committed和Repeatable Read
- Read Uncommitted无需MVCC
- 只靠MVCC无法实现Serializable
基本思想
脏读和不可重复读问题的根本原因
- 未满足隔离性,事务可以读取到其它事务未提交的修改
相关概念
系统版本号(SYS_ID)
- 每开始一个新的事务,系统版本号就会自动递增
事务版本号(TRX_ID)
- 事务开始时的系统版本号
版本快照
MVCC的要求
- 修改操作(DELETE、INSERT、UPDATE)会为数据行新增一个版本快照
- 写操作更新最新的版本快照
- 读操作读旧版本快照
- 只能读取已经提交的快照
Undo日志
结构
- 多个版本的快照存储在Undo日志中
- 日志通过回滚指针ROLL_PTR把一个数据行的快照连起来
栗子
操作
1
2
3INSERT INTO t(id, x) VALUES(1, "a");
UPDATE t SET x="b" WHERE id=1;
UPDATE t SET x="c" WHERE id=1;过程
Del字段标记删除操作
ReadView
内容
- 当前系统未提交的事务列表(TRX_IDs )
- TRX_ID_MIN、TRX_ID_MAX
读操作过程
TRX_ID < TRX_ID_MIN
- 该数据行快照是在当前所有未提交事务之前进行更改的,因此可以使用
TRX_ID > TRX_ID_MIN
- 表示该数据行快照是在事务启动之后被更改的,因此不可使用
TRX_ID_MIN <= TRX_ID <= TRX_ID_MAX
Read Committed
TRX_ID in TRX_IDs
- 该数据行快照对应的事务还没提交,所以NO
TRX_ID not in TRX_IDs
- 该数据行快照对应的事务已经提交,所以YES
Repeatable Read
No matter what, No
为了避免不可重复读
快照读与当前读
快照读
MVCC的Select读的是快照中的数据,无需加锁
也可以手动加锁:
1
2SELECT * FROM table WHERE ? lock in share mode;
SELECT * FROM table WHERE ? for update;
当前读
- INSERT、UPDATE、DELETE需要进行加锁
Phantom Read问题
MVCC不能解决Phantom Read问题:
MVCC只能解决快照读的幻读问题,不能解决当前读的幻读问题
行锁
Record Locks
- 锁定一个记录上的索引 而不是记录本身
Gap locks
- 锁定索引之间的间隙
Next-Key locks
不仅锁定一个记录上的索引,也锁定索引之间的间隙
概念
- InnoDB存储引擎的一种锁实现
作用
- 使用MVCC+Next-Key Locks可以在Repeatable Read级别下解决幻读问题