Django的:避免值基于聚集现场竞态条件

问题描述 投票:0回答:1

有例子模型:

class MyModel(models.Model):
    name = models.CharField()
    version = models.IntegerField()

我需要根据同名实例的最大版本设置version字段值。要做到这一点,我重写save方法:

   def save(self, *args, **kwargs):
       max_version = MyModel.objects \
           .filter(name=self.name) \
           .aggregate(max_version=Max('version'))['max_version'] or 0
       self.version = max_version + 1
       super(MyModel, self).save(*args, **kwargs)

如何避免竞争条件吗?

编辑:版本必须是唯一的(同名实例之间),但为了不是太重要。

django race-condition
1个回答
0
投票

我认为,一个简单的原子transaction应该解决您的问题。

from django.db import transaction


def save(self, *args, **kwargs):
    with transaction.atomic():
        max_version = MyModel.objects \
           .filter(name=self.name) \
           .aggregate(max_version=Max('version'))['max_version'] or 0
        self.version = max_version + 1
        super(MyModel, self).save(*args, **kwargs)

虽然出实际问题的范围,您可能希望只在创建记录(保存的第一次)来更新version领域。你可以做到这一点通过验证pkNone这样。

from django.db import transaction


def save(self, *args, **kwargs):
    if self.pk is None:
        with transaction.atomic():
            max_version = MyModel.objects \
               .filter(name=self.name) \
               .aggregate(max_version=Max('version'))['max_version'] or 0
            self.version = max_version + 1
            super(MyModel, self).save(*args, **kwargs)

    else:
        super(MyModel, self).save(*args, **kwargs)
© www.soinside.com 2019 - 2024. All rights reserved.