竞争条件下的 INSERT-SELECT 和 UPDATE
INSERT-SELECTs and UPDATEs in race conditions
#1:如果我 运行
INSERT INTO foo SELECT MAX(X) FROM bar;
我可以确定我刚刚从 bar
table 中插入了 X
列的最大值吗?在 SELECT
部分完成之后但在 INSERT
完成之前,没有其他会话设法操纵 bar
table 吗?
#2:如果我运行
UPDATE foo SET x = 0 WHERE y = 100;
当时钟到达 00:00 并且查询需要 2 分钟时,我可以确定在 00:00 处具有 y = 100
的所有行都已更新吗?在我的查询完成之前没有其他会话设法将 y = 100
更改为 y = 80
?
#3:这与#2有关。如果在 00:01 另一个会话通过将 y = 99
更改为 y = 100
对一行执行 UPDATE
s,我之前的查询是否尝试 UPDATE
这一行?
事务用于保证数据库的状态。可重复读取,因此当读取最大值时,您可以一次又一次地读取它,它会保持不变。
那你设置交易
https://dev.mysql.com/doc/refman/5.6/en/set-transaction.html
然后你的代码更新 x = (select max(y) from z)
然后你提交交易
我可能漏掉了一些东西,但通常情况下,它是如何进行精确报告的。
如果您不使用显式事务,则每个查询本身都被视为一个事务。因此,结合 INSERT
和 SELECT
的查询(如您的#1)可能取决于一致性。大致相当于:
START TRANSACTION;
SET @max = (SELECT MAX(x) FROM bar);
INSERT INTO foo VALUES (@max);
COMMIT;
但是,事务不会在事务开始时创建整个数据库的快照。 InnoDB 使用每记录锁定。因此,在#2 和#3 中,如果会话 A 更新 y
而会话 B 执行您显示的查询,则 B 更新的记录可能会或可能不会包括 A 修改的记录,具体取决于 A 的相对顺序那些具体的变化。另一方面,MyISAM 使用 table 级别的锁,所以这应该是不可能的;无论哪个查询先启动,都会锁定 foo
table,而另一个查询将等待它完成,然后再开始扫描 table.
#1:如果我 运行
INSERT INTO foo SELECT MAX(X) FROM bar;
我可以确定我刚刚从 bar
table 中插入了 X
列的最大值吗?在 SELECT
部分完成之后但在 INSERT
完成之前,没有其他会话设法操纵 bar
table 吗?
#2:如果我运行
UPDATE foo SET x = 0 WHERE y = 100;
当时钟到达 00:00 并且查询需要 2 分钟时,我可以确定在 00:00 处具有 y = 100
的所有行都已更新吗?在我的查询完成之前没有其他会话设法将 y = 100
更改为 y = 80
?
#3:这与#2有关。如果在 00:01 另一个会话通过将 y = 99
更改为 y = 100
对一行执行 UPDATE
s,我之前的查询是否尝试 UPDATE
这一行?
事务用于保证数据库的状态。可重复读取,因此当读取最大值时,您可以一次又一次地读取它,它会保持不变。
那你设置交易
https://dev.mysql.com/doc/refman/5.6/en/set-transaction.html
然后你的代码更新 x = (select max(y) from z)
然后你提交交易
我可能漏掉了一些东西,但通常情况下,它是如何进行精确报告的。
如果您不使用显式事务,则每个查询本身都被视为一个事务。因此,结合 INSERT
和 SELECT
的查询(如您的#1)可能取决于一致性。大致相当于:
START TRANSACTION;
SET @max = (SELECT MAX(x) FROM bar);
INSERT INTO foo VALUES (@max);
COMMIT;
但是,事务不会在事务开始时创建整个数据库的快照。 InnoDB 使用每记录锁定。因此,在#2 和#3 中,如果会话 A 更新 y
而会话 B 执行您显示的查询,则 B 更新的记录可能会或可能不会包括 A 修改的记录,具体取决于 A 的相对顺序那些具体的变化。另一方面,MyISAM 使用 table 级别的锁,所以这应该是不可能的;无论哪个查询先启动,都会锁定 foo
table,而另一个查询将等待它完成,然后再开始扫描 table.