没有锁定的事务中读取过滤器写入的可能失败模式有哪些?

时间:2015-07-16 05:21:24

标签: mysql database transactions innodb acid

考虑以下工作流程,使用InnoDB引擎在MySQL中运行。

  1. 开始交易。
  2. 使用SELECT FROM tablename WHERE ...选择一些行,而不是SELECT ... FOR UPDATE
  3. 使用未在数据库中执行的代码过滤这些行(比方说Python)。
  4. 对某些行子集执行DELETE
  5. 结束交易。
  6. 基于this question,由于步骤2,此工作流程似乎并不安全,但答案并未提供有关故障模式的详细信息。

    这是简单的未定义行为,还是有一组特定的,明确定义的失败模式?

    此外,为什么交易的ACID性质不能防止不安全行为?

2 个答案:

答案 0 :(得分:0)

DELETEs始终是安全的。例如,考虑一个队列,其中SELECT提取某些“工作”,而DELETE表示工作已完成。此外,让我们说如果工作完成两次就会发生令人讨厌的事情。 (也许像递增计数器一样简单的是其他表。)如果没有FOR UPDATE,两个线程可以从队列中获取相同的项目;一个DELETE会删除该行;另一个会删除零行(你可能不会注意到它)。

相反,如果步骤3涉及UPDATEing一些行;你有可能在行上抛出相互冲突的更新。

这是两种“失败模式”。请注意,它们实际上是应用程序或数据故障,而不是MySQL“故障”。没有FOR UPDATE,MySQL很乐意“做错事”。

想到FOR UPDATE说“这是我的;请保持双手!”

答案 1 :(得分:0)

当它与其他两个事务交错时,我最终发现这个场景存在更严重的问题,导致删除意外数据。下面介绍了此方案,其中name是主键,gender是另一列。

交易1

  1. DELETE FROM people WHERE name="foo";
  2. 交易2

    1. SELECT name, gender FROM people WHERE name="foo";
    2. (应用程序逻辑)If gender == female, then return
    3. DELETE FROM people WHERE name="foo" //根据应用程序逻辑,观察的目的是仅在foo为男性时删除foo
    4. 交易3

      1. INSERT INTO people (name, gender) VALUES("foo", "female")
      2. 通过以下交错交易,我们最终会从表中删除女性foo,这不是应用程序的意图。

        2.1, 2.2, 1, 3, 2.3
        

        使用SELECT...FOR UPDATE,这不会发生,因为SELECT会阻止1.13.1发生。