在竞争条件下进行INSERT-SELECT和UPDATE

时间:2018-11-07 22:51:20

标签: mysql race-condition simultaneous

#1:如果我跑步

INSERT INTO foo SELECT MAX(X) FROM bar;

是否可以确定我刚刚插入了X表中bar列的最大值?在bar部分完成之后但在SELECT完成之前,没有其他会话能够操纵INSERT表吗?

#2:如果我跑步

UPDATE foo SET x = 0 WHERE y = 100;

当时钟达到00:00且查询需要2分钟时,我是否可以确定所有在00:00带有y = 100的行都已更新?在我的查询完成之前,没有其他会话设法将y = 100更改为y = 80吗?

#3:与#2有关。如果在00:01,另一个会话通过将UPDATE更改为y = 99而将y = 100移至一行,那么我先前的查询是否尝试UPDATE移至该行?

2 个答案:

答案 0 :(得分:1)

如果您不使用显式事务,则每个查询本身都会被视为事务。因此,像您的#1一样结合了INSERTSELECT的查询可能取决于一致性。大致相当于:

START TRANSACTION;
SET @max = (SELECT MAX(x) FROM bar);
INSERT INTO foo VALUES (@max);
COMMIT;

但是,在事务开始时,事务不会创建整个数据库的快照。 InnoDB使用每条记录锁定。因此,在#2和#3中,如果会话A执行您显示的查询时会话A正在更新y,则B更新的记录可能包括也可能不包括由A修改的记录,具体取决于记录的相对顺序。这些具体的变化。另一方面,MyISAM使用表级锁,因此这不可能。首先开始的查询将锁定foo表,而另一个查询将等待其完成才开始扫描表。

答案 1 :(得分:0)

事务用于保证数据库状态。可重复读取,因此当读取最大值时,您可以再次读取它,并且它将保持不变。

https://dev.mysql.com/doc/refman/5.6/en/innodb-transaction-isolation-levels.html#isolevel_repeatable-read

然后您设置交易

https://dev.mysql.com/doc/refman/5.6/en/set-transaction.html

然后您的代码更新x =(从z中选择max(y))

然后您提交交易

我可能错过了一些东西,但总的来说,这就是以前的举报方式。