0

我想执行以下两个 MySQL 语句:

1) SELECT * FROM table1 WHERE field1=val1 FOR UPDATE;
2) UPDATE table1 SET field2=val2 WHERE field1=val1;

重要的是,第二个语句准确地更改了第一个语句返回的行(没有额外的行,也没有更少的行)。因此,我使用 auto_commit=false 执行事务并使用 select 语句的“for update”版本。

“For Update”会锁定它返回的所有行,因此在执行第二条语句时它们处于原始状态。但是插入呢?是否有可能另一个线程插入一个新行,其间有 field1=val1,然后被第二条语句更改?

还有一个问题:如果第二条语句不改变行本身,但执行以下操作,是否会有所不同?

3) INSERT INTO table2 (SELECT * FROM table1 WHERE field1=val1)

如果(3)与(1)在同一个事务中,那么确保两个选择返回完全相同的元素吗?

编辑:

我正在使用 InnoDB 并且我阅读了一些关于下一个键锁定和间隙锁定的内容。据我了解,在执行(1)时,InnoDB 不仅会锁定选定的行,还会锁定访问的索引。

那么我是否可以说如果我在列“field1”上有一个索引就不会发生这个问题?如果没有索引怎么办?那不一样了吗?

4

1 回答 1

1

我不能完全谈论 mySQL 案例,但我对此表示怀疑。SELECT FROM ... FOR UPDATE(似乎)要做的唯一一件事是防止其他事务修改给定的一组行。它不限制未来的语句 - 如果在该UPDATE语句运行之前(由另一个事务)插入另一行,它也会被更新。
不用说,您给出的第三个陈述也将成为同一问题的牺牲品。

你想在这里实际做什么?可能还有另一种方法可以实现这一点。例如,如果有某种“insertedAt”时间戳,您可能只需将其添加为额外条件。

于 2012-11-16T16:56:23.727 回答