考虑以下工作流程,使用InnoDB引擎在MySQL中运行。
SELECT FROM tablename WHERE ...
选择一些行,而不是SELECT ... FOR UPDATE
。 DELETE
。 基于this question,由于步骤2,此工作流程似乎并不安全,但答案并未提供有关故障模式的详细信息。
这是简单的未定义行为,还是有一组特定的,明确定义的失败模式?
此外,为什么交易的ACID性质不能防止不安全行为?
答案 0 :(得分:0)
DELETEs
始终是安全的。例如,考虑一个队列,其中SELECT
提取某些“工作”,而DELETE
表示工作已完成。此外,让我们说如果工作完成两次就会发生令人讨厌的事情。 (也许像递增计数器一样简单的是其他表。)如果没有FOR UPDATE
,两个线程可以从队列中获取相同的项目;一个DELETE
会删除该行;另一个会删除零行(你可能不会注意到它)。
相反,如果步骤3涉及UPDATEing
一些行;你有可能在行上抛出相互冲突的更新。
这是两种“失败模式”。请注意,它们实际上是应用程序或数据故障,而不是MySQL“故障”。没有FOR UPDATE
,MySQL很乐意“做错事”。
想到FOR UPDATE
说“这是我的;请保持双手!”
答案 1 :(得分:0)
当它与其他两个事务交错时,我最终发现这个场景存在更严重的问题,导致删除意外数据。下面介绍了此方案,其中name
是主键,gender
是另一列。
交易1
DELETE FROM people WHERE name="foo";
交易2
SELECT name, gender FROM people WHERE name="foo";
If gender == female, then return
。DELETE FROM people WHERE name="foo"
//根据应用程序逻辑,观察的目的是仅在foo
为男性时删除foo
。交易3
INSERT INTO people (name, gender) VALUES("foo", "female")
通过以下交错交易,我们最终会从表中删除女性foo
,这不是应用程序的意图。
2.1, 2.2, 1, 3, 2.3
使用SELECT...FOR UPDATE
,这不会发生,因为SELECT
会阻止1.1
和3.1
发生。