背景
Mysql使用MVCC机制,在可重复度隔离级别下解决了绝大部分幻读问题。
但有一个特殊场景会导致幻读:当前读
。
快照读
使用最初的ReadView
当前读
使用最新的ReadView。
同一个事务中可以同时存在快照读
和当前读
。
表结构
CREATE TABLE `test_index` (
`a` int NOT NULL AUTO_INCREMENT,
`b` int DEFAULT NULL,
`c` int DEFAULT NULL,
PRIMARY KEY (`a`),
KEY `idx_b` (`b`)
) ENGINE=InnoDB CHARSET=utf8mb4;
准备数据
insert into test_index (a, b, c) VALUES (1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),(6,6,6);
使用当前读触发幻读
用Tn表示sql执行的先后顺序
分别在3个事务中执行sql
-- T1时刻
-- 事务1
begin ;
insert into test_index values (9,2,2);
-- T2时刻
-- 事务2
begin ;
insert into test_index values (10,4,4);
-- T3时刻
-- 事务3
-- 生成ReadView1
-- 查询到(2,2,2)
begin ;
select * from test_index where b = 2;
-- T4时刻
-- 事务1
commit ;
-- T5时刻
-- 事务3
-- 这是当前读,生成最新的ReadView2。
-- 同一个事务中,读到了新插入的数据。
-- 查询到(2,2,2) 和 (9,2,2)
select * from test_index where b = 2 for update;
-- T6时刻
-- 事务3
-- 这是快照读,使用ReadView1
-- 查询到(2,2,2)
select * from test_index where b = 2;
-- T7时刻
-- 事务2
commit ;
-- T8时刻
-- 事务3
-- 这是当前读,生成最新的ReadView3。
-- 同一个事务中,读到了新插入的数据。
-- 查询到(4,4,4) 和 (10,4,4)
select * from test_index where b = 4 for update;
-- T9时刻
-- 事务3
-- 这是快照读,使用ReadView1
-- 查询到(4,4,4)
select * from test_index where b = 4;