【问题标题】:Django MySQL REPEATABLE READ "data loss"Django MySQL REPEATABLE READ“数据丢失”
【发布时间】:2019-12-14 21:28:00
【问题描述】:

我正在寻找有关Django 2.0 release notes 条目背后的信息。说明:

MySQL 的默认隔离级别,可重复读取,在典型的 Django 使用中可能会导致数据丢失。为了防止这种情况并为了与其他数据库保持一致,默认隔离级别现在是已提交读。如果需要,您可以使用 DATABASES 设置来使用不同的隔离级别。

据我了解,可重复读取比已提交读取“更严格”,所以 Django 正在做什么来产生“数据丢失”是一个困扰我一段时间的问题。

是像prefetch_related 这样的东西吗?或者,一般来说,基于潜在陈旧(线程中的SELECTED)制作UPDATE 是或可以被认为是数据丢失?或者甚至更好——也许只有 MySQL 会做一些事情,或者有一个错误会使其在可重复读取时变得危险?

谢谢。

【问题讨论】:

  • 关于“隔离级别”的文档说:“特别是,您可能会看到 get_or_create() 会引发 IntegrityError 但该对象不会出现在随后的 get() 调用中的情况。”

标签: mysql django transactions isolation-level


【解决方案1】:

REPEATABLE READ 实际上有两个问题在这里值得注意。

其中之一是 Django 的内部代码编写时期望事务遵守READ COMMITTED 语义。 REPEATABLE READ 实际上是更高的隔离级别这一事实并不重要;关键是它违反了Django代码的期望,导致不正确的行为。 (实际上,添加一个设置来更改隔离级别是initially resisted,因为“这意味着 Django 在任何隔离级别下都能正常工作,我认为这不是真的”。)

一个简单的例子(9 年前问题跟踪器中的first noted)是get_or_create() 的行为。它works 首先尝试读取该行;然后,如果失败,请尝试创建它。如果该创建操作失败,可能是因为其他一些事务同时创建了该行。因此,它再次尝试读取并返回它。这在 READ COMMITTED 中按预期工作,但在 REPEATABLE READ 中,最终读取将找不到任何内容,因为读取必须返回与第一次找到的结果相同的结果(无)。

不过,这不是数据丢失。第二个问题特定于 MySQL 以及它定义 REPEATABLE READ 行为的非标准方式。粗略地说,读取的行为类似于REPEATABLE READ,但写入的行为类似于READ COMMITTED,这种组合会导致数据丢失。最好用一个例子来说明这一点,所以让我引用核心贡献者 Shai Berger 提供的this one

(1) BEGIN TRANSACTION

(2) SELECT ... FROM some_table WHERE some_field=some_value  
     (1 row returned)

(3) (some other transactions commit)

(4) SELECT ... FROM some_table WHERE some_field=some_value
     (1 row returned, same as above)

(5) DELETE some_table WHERE some_field=some_value
     (answer: 1 row deleted)

(6) SELECT ... FROM some_table WHERE some_field=some_value
     (1 row returned, same as above)

(7) COMMIT
     (the row that was returned earlier is no longer in the database)

请花一分钟时间阅读本文。到第(5)步,一切都如你所愿; 您应该会发现步骤 (6) 和 (7) 非常令人惊讶。

发生这种情况是因为 (3) 中的其他事务删除了 在 (2)、(4) 和 (6) 中返回,并在其中插入另一个 some_field=some_value;另一行是在 (5) 中删除的行。这 DELETE 没有看到此事务选择的行,因此看不到 由它更改,因此在我们的 SELECTs 中继续可见 交易。但是当我们提交时,该行(已被删除)不再 存在。

导致默认隔离级别发生这种变化的tracker issue 提供了有关该问题的更多详细信息,如果您想了解更多信息,它还链接到其他讨论和问题。

【讨论】:

    猜你喜欢
    • 2017-07-28
    • 2013-12-22
    • 2022-09-23
    • 1970-01-01
    • 2015-01-31
    • 2012-01-07
    • 1970-01-01
    • 2012-04-07
    • 1970-01-01
    相关资源
    最近更新 更多