【问题标题】:Django concurrent get_or_createDjango 并发 get_or_create
【发布时间】:2015-06-09 09:10:53
【问题描述】:

我担心一件事。
使用 Django 1.7(最默认安装中的 MySQL)我正在向 Django REST Framework APIView 进行 POST。 在那边我正在做一个:

try:
    MyModel.objects.get(**some_kwargs)
except MyModel.DoesNotExist:
    MyModel.objects.custom_create(**some_kwargs)  # This also creates relative models

现在,如果我要执行大量并发请求会怎样?
正如我猜你所期望的那样,我只想要第一个并发请求来创建一个对象,而其他任何人都应该得到创建的那个。

感谢 Django,我准备好了吗?必须研究隔离、事务、原子性?或者更多的是关于锁定桌子?如何(单元)测试它?

请指导我。

【问题讨论】:

    标签: python mysql django transactions atomic


    【解决方案1】:

    这不足以避免竞争条件,因为另一个请求可以创建您打算在 get()custom_create() 之间检索的模型。如果在数据库级别强制执行唯一性,您的custom_create() 方法可能会失败并返回IntegrityError。如果不是,则您的方法很好,但您无法防止由于竞争条件而出现重复条目​​。

    Django 提供了get_or_create() 函数。如果您的数据库强制执行唯一性,这可以防止出现竞争条件。它使用create() 方法,但是,不是您的custom_create() 方法,因此如果可以接受,您必须覆盖它。否则,您可以签出 source code for get_or_create() 并使用您的自定义创建方法自行实现。

    get_or_create 的核心假设是在数据库级别强制执行唯一性。由于这种强制措施,如果出现竞争条件,create 将失败,get_or_create 可以回退到获取在竞争条件期间创建的对象。如果缺少此强制措施,create 在竞争条件下不会失败,并且将创建一个重复条目(具有不同的 PK)。

    【讨论】:

    • 仍然没有运气:(现在我正在尝试 postgresql 和相同的效果(在 MySQL 上也尝试过 READ COMMITTED)和一个简单的 MyModel.objects.get_or_create 由 Django 提供 - 有时它可以(只有一个创建)和有时第二个线程会再次创建,然后第三个线程会抛出 MultipleObjectsReturned。用这个进行测试:caktusgroup.com/blog/2009/05/26/…
    • @McAbra 您是否在数据库级别强制**some_kwargs 的唯一性?否则,没有明智的方法来防止重复。
    • 我刚刚在该模型的所有三个属性上都创建了一个unique_together,但它没有帮助,你是这么说的吗?
    • @McAbra 是的。而且您问题中的代码永远不会抛出IntegrityError!?
    • 是的。使用custom_create 或现在使用默认get_or_create 时都没有得到IntegrityError。我正在对一个简单的视图执行这些并发 POST 请求,我得到的只是MultipleObjectsReturned
    猜你喜欢
    • 2017-11-05
    • 2018-05-12
    • 1970-01-01
    • 2016-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-18
    相关资源
    最近更新 更多