Django 增量字符串值,没有竞争条件

Django increment string value without race condition

提问人:Arti 提问时间:11/10/2023 最后编辑:Arti 更新时间:11/13/2023 访问量:50

问:

在保存时,我想收到像 .我实现了以下代码:name, name(1), name(2)

        with transaction.atomic():
            same_name_count = Folder.objects.filter(
                owner=validated_data["owner"],
                name__iregex=r"%s(\s\(\d+\))?" % validated_data["name"],
            ).count()

            if same_name_count:
                validated_data["name"] = f"{validated_data['name']} ({same_name_count+1})"

            folder = Folder.objects.create(**validated_data)

但是当我在芹菜任务中运行此代码时,我仍然收到竞争条件并收到相同的名称。我还尝试以某种方式锁定所有行并获得正确的计数select_to_update

我的模型如下所示:

class Folder(models.Model):
    owner = models.ForeignKey('User')
    name = models.CharField(max_length=255)
MySQL Django 事务

评论

0赞 Bartosz Stasiak 11/10/2023
我不;t 了解竞争条件在哪里。您能否举例说明这段代码输出的内容以及它应该输出的内容?
0赞 Arti 11/10/2023
当我使用此代码运行 2 个芹菜任务时,我收到具有相同编号的名称,例如 和 .当然,这只是在生产环境中,当芹菜任务 CELERY_TASK_ALWAYS_EAGER=False 时name(1)name(1)
0赞 Bartosz Stasiak 11/10/2023
您可以共享文件夹模型结构吗?什么是所有者字段?
0赞 Arti 11/10/2023
''' 类 Folder(models.Model):所有者 = 模型。ForeignKey('User') 名称 = 模型。CharField(max_length=255) '''
0赞 Bartosz Stasiak 11/10/2023
更新问题并将其放在那里

答:

3赞 Bartosz Stasiak 11/10/2023 #1

select_for_update将锁定表中所有选定的行,但不会阻止添加新行。

您需要做的是锁定其他表中的行。这样,事务将等到此锁定行被解锁。

在您的情况下,最合适的是桌子。User

示例代码如下:

    with transaction.atomic():
        # Assuming validated_data["owner"] is an id of the user. 
        # If its the User objects then add .id at the end
        folder_owner = User.objects.select_for_update().get(id=validated_data["owner"])

        same_name_count = Folder.objects.filter(
            owner=folder_owner,
            name__iregex=r"%s(\s\(\d+\))?" % validated_data["name"],
        ).count()

        if same_name_count:
            validated_data["name"] = f"{validated_data['name']} ({same_name_count+1})"

        folder = Folder.objects.create(**validated_data)

评论

0赞 Bill Karwin 11/10/2023
MySQL 还具有获取建议锁的功能,请参阅 dev.mysql.com/doc/refman/8.0/en/locking-functions.html。这使用与表锁相同的机制,但不会锁定任何表或行。
0赞 Arti 11/10/2023
谢谢,没想到我需要锁定用户以防止插入。它正在工作