首页 > 解决方案 > 防止 INSERT INTO ... SELECT 语句创建自己的新快照

问题描述

MySQL/MariaDb InnoDb 引擎是否可以执行INSERT INTO ... SELECT语句并使用当前REPEATABLE READ事务创建的快照?

示例(所有语句在一个会话中运行,除了下面提到的一个):

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION; -- snapshot 1 for this transaction is created
SELECT * FROM t1; -- result is 1 row, snapshot 1 is used
-- another transaction (different session) inserts and commits new row into t1 table
SELECT * FROM t1; -- result is still 1 row, because its REPEATABLE READ, still using snapshot 1
INSERT INTO t2 SELECT * FROM t1; -- this SELECT creates new snapshot 2
SELECT * FROM t2; -- result are 2 rows
SELECT * FROM t1; -- result is still 1 row, using snapshot 1

是否可以制作这条线:

INSERT INTO t2 SELECT * FROM t1; -- this SELECT creates new snapshot 2

...使用快照 1?以及为什么 MySQL 会这样。这不违反隔离原则吗?

此处记录了此行为https://dev.mysql.com/doc/refman/8.0/en/innodb-consistent-read.html

对于未指定 FOR UPDATE 或 FOR SHARE 的子句中的选择,例如 INSERT INTO ... SELECT、UPDATE ... (SELECT) 和 CREATE TABLE ... SELECT,读取的类型会有所不同:

默认情况下,InnoDB 使用更强的锁,并且 SELECT 部分的行为类似于 READ COMMITTED,其中每个一致的读取,即使在同一个事务中,设置和读取自己的新快照

以下是上面使用的一些可能的表结构:

CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; 
CREATE TABLE t2 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;

唯一重要的是 InnoDB 引擎。

标签: mysqlinnodbtransaction-isolation

解决方案


推荐阅读