没有竞争条件的Django中的条件更新

时间:2015-10-18 21:41:23

标签: django transactions

如何根据当前值更新模型字段并避免竞争条件?更新任务可以写为:

if (self.x == y):
    self.x = z
    self.save()
else:
    raise Exception()

然而,存在竞争条件。我提出了以下解决方案:

from django.db import transaction
with transaction.atomic():
    if (self.x == y):
        self.x = z
        self.save()
    else:
        raise Exception()

但是这样安全且有更好的方法吗?

1 个答案:

答案 0 :(得分:3)

不,atomic()阻止无法执行任何操作,因为您在尝试运行事务之前已经从数据库中获取了值self

如果您可以在查询参数中表达条件,则可以使用update()在单个查询中安全地执行此操作:

num_matched = MyModel.objects.filter(id=self.id, x=y).update(x=z)
if num_matched != 1:
    raise Exception()

如果没有,您可以使用select_for_update()

with transaction.atomic():
    current = MyModel.objects.select_for_update().get(id=self.id)
    if (current.x == y):
        current.x = z
        current.save()
    else:
        raise Exception()

这与上面的代码之间的区别在于,您在进行比较之前,明确告诉数据库要锁定哪一行。