【问题标题】:Race condition when Django model creationDjango模型创建时的竞争条件
【发布时间】:2015-06-10 19:35:47
【问题描述】:

我有这样的模型:

class Deck(models.Model):
    some_hash = models.CharField(max_length=64)
    store_id = models.CharField(max_length=256)
    tier = models.IntegerField()

class Card(models.Model):
    deck = models.ForeignKey(Deck, related_name='cards')

还有一个应该做这样的事情的视图:

class GetCardView(ApiView):  # ApiView from Django REST Framework
    response_json = get_some_data_from_external_service(
        request.GET['store_id'], request.GET['tier']
    )  # if this data for a store_id and tier changes a new Deck is needed

    deck, created = Deck.objects.get_or_create(
        some_hash=hashlib.sha256(response).hexdigest(), 
        store_id=request.GET['store_id'], tier=request.GET['tier']
    )
    if created:
        deck.add_cards(response_json)  # adds for e.g. 5 cards

    card = deck.pick_a_card()
    if not card: #  deck depleted
        Deck.objects.create(
            some_hash=hashlib.sha256(response).hexdigest(), 
            store_id=request.GET['store_id'], tier=request.GET['tier']
        )
        deck.add_cards(response_json)  # adds for e.g. 5 cards
        card = deck.pick_a_card()
    return Response(card)

我知道这种观点很丑陋,但表明了我想要做的事情。
现在的问题是当并发请求出现时如何保护我自己免受竞争条件的影响?锁定桌子是唯一的方法吗? Django 1.7.7,MySQL(事务设置为:READ COMMITED)

【问题讨论】:

  • Django如何让你指定“事务”的BEGIN和COMMIT?我在您的代码中没有看到任何提示。
  • 您可以简单地在__enter__ 上执行with transaction.atomic(): - BEGIN,COMMIT 上__exit__,ROLLBACK 上的异常。
  • 可以通过包装事务并在SELECTs 上使用FOR UPDATE 来处理许多“竞争条件”,从而导致执行UPDATE。
  • 你可以在这里找到答案:stackoverflow.com/questions/2235318/…

标签: mysql django concurrency transactions locking


【解决方案1】:

所以我并没有真正找到答案,因为现在我认为这个想法从一开始就很糟糕。
我最终没有存储 Card 模型,我选择了那些使用 LFSR 并且只将种子存储在 Deck 模型中。这对我来说已经足够了。

供日后参考。您需要在数据库级别失败的东西(例如唯一约束),这会引发一些异常,您的逻辑可以在 transaction.atomic() 上下文管理器中识别这些异常。

READ-COMMITTED 隔离级别的 MySQL 适用于get_or_create。

感谢大家提供的信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-17
    • 2010-09-29
    • 1970-01-01
    • 2012-11-24
    • 2023-03-30
    • 2019-02-15
    • 1970-01-01
    • 2019-03-21
    相关资源
    最近更新 更多