【发布时间】:2019-07-28 17:32:00
【问题描述】:
我想创建一个模型,其 ID 等于该模型的当前最大 ID 加一(如自动增量)。我正在考虑使用select_for_update 执行此操作,以确保当前最大 ID 没有竞争条件,如下所示:
with transaction.atomic():
greatest_id = MyModel.objects.select_for_update().order_by('id').last().id
MyModel.objects.create(id=greatest_id + 1)
但我想知道,如果两个进程尝试同时运行它,一旦第二个进程解除阻塞,它会看到第一个进程插入的新的最大 ID,还是仍会看到旧的最大 ID?
例如,假设当前最大的 ID 是 10。两个进程去创建一个新模型。第一个锁定 ID 10。然后第二个阻塞,因为 10 被锁定。第一个插入 11 并解锁 10。然后,第二个解除阻塞,现在它会看到第一个插入的 11 是最大的,还是仍然会看到 10,因为那是它阻塞的行?
在 select_for_update docs 中,它说:
通常,如果另一个事务已经在其中一个选定的行上获得了锁,则查询将阻塞,直到锁被释放。
因此,对于我的示例,我认为这意味着第二个进程将在解除阻塞并获得 11 后重新运行最大 ID 的查询。但我不确定我的解释是否正确。
注意:我使用 MySQL 作为数据库。
【问题讨论】:
-
作为替代方案,考虑使用乐观并发。有关更多详细信息,请参阅my answer here。正如我在那里所说:“如果碰撞很少,这种方法可以很好地工作,如果碰撞频繁,这种方法就很糟糕。”
-
是的,我不希望经常发生碰撞,所以我实际上打算使用它。非常感谢您的帮助。
标签: mysql django django-models django-queryset django-orm