为何带子查询的SELECT ... FOR UPDATE会创建快照,INSERT ... SELECT却不会?
MySQL InnoDB可重复读隔离级别下一致性快照(Read View)的创建时机问题
测试场景
测试使用两张表,表结构如下:
CREATE TABLE table1 ( name VARCHAR(100) NOT NULL, INDEX idx_table1_name (name) ); CREATE TABLE table2 ( name VARCHAR(100) NOT NULL, INDEX idx_table2_name (name) );
案例1:带子查询的SELECT ... FOR UPDATE
事务1执行:
START TRANSACTION; SELECT * FROM table1 WHERE name = ( SELECT name FROM table2 WHERE name = 'a' ) FOR UPDATE;
事务2执行:
START TRANSACTION; INSERT INTO table2 VALUES ('b'); COMMIT;
回到事务1执行:
SELECT * FROM table2 WHERE name = 'b'; -- 返回空集
现象分析:该结果表明带子查询的SELECT ... FOR UPDATE执行时已创建一致性快照,因此无法看到事务2提交的新数据'b'。
案例2:带子查询的INSERT INTO ... SELECT
事务1执行:
START TRANSACTION; INSERT INTO table1 SELECT 'c' FROM table2 WHERE name = 'a';
事务2执行:
START TRANSACTION; INSERT INTO table2 VALUES ('b'); COMMIT;
回到事务1执行:
SELECT * FROM table2 WHERE name = 'b'; -- 返回'b'
现象分析:该结果说明INSERT INTO ... SELECT未创建一致性快照,能够看到事务2提交的新数据。根据官方文档,常规SELECT ... FOR UPDATE属于DML操作而非普通查询。
问题
- 为何带子查询的
SELECT ... FOR UPDATE会创建快照? - 为何同处于可重复读隔离级别,
INSERT INTO ... SELECT却不创建快照? - 该行为是否在MySQL官方文档中有记载?
- 快照的创建时机是否取决于DML中是否存在子查询?
内容的提问来源于stack exchange,提问作者samsamsamsmasma
相关产品推荐
相关产品推荐

