在Django中处理eauction玩具应用程序的并发处理的最佳方法

时间:2011-06-08 22:10:26

标签: django concurrency

我正在Django中实现一个eauction玩具应用程序,并且对于如何在下面的代码中最好地处理并发性感到困惑。我不确定哪些候选解决方案(或任何其他方案)最适合Django的设计。我是Django / python的新手,而且我的SQL专有技术是生锈的,所以如果这是一个不用脑子的道歉。

要求:用户可以对产品出价。只有在同一产品的出价高于之前的出价时才会接受出价。

以下是模型的精简版本:

class Product(models.Model):
    name = models.CharField(max_length=20)

class Bid(models.Model):
    amount = models.DecimalField(max_digits=5, decimal_places=2)
    product = models.ForeignKey(Product)

和出价视图。这就是竞争条件发生的地方(见评论):

def bid(request, product_id):
    p = get_object_or_404(Product, pk=product_id)
    form = BidForm(request.POST)
    if form.is_valid():
        amount = form.cleaned_data['amount']

        # the following code is subject to race conditions
        highest_bid_amount = Bid.objects.filter(product=product_id).aggregate(Max('amount')).get('amount__max')
        # race condition: a bid might have been inserted just now by another thread so highest_bid_amount is already out of date
        if (amount > highest_bid_amount):
            bid = Bid(amount=amount, product_id=product_id)
            # race condition: another user might have just bid on the same product with a higher amount so the save() below is incorrect
            b.save()
            return HttpResponseRedirect(reverse('views.successul_bid)'

到目前为止我考虑的解决方案候选人:

  1. 我已阅读有关交易的Django文档,但我不知道如何将它们应用于我的问题。由于数据库不知道出价必须提升的要求,因此不会导致Django抛出IntegrityError。有没有办法在模型定义期间定义此约束?或者是否误解了交易API?
  2. 存储过程可以处理出价逻辑。到目前为止,这似乎是“最佳”选择,但它将处理竞争条件转移到底层数据库系统。但是,如果这是一个很好的方法,这个解决方案可能会与解决方案1?
  3. 结合使用
  4. 我考虑过使用select_for_update来锁定此产品的出价。但是,这似乎不是一个解决方案,因为根据我的理解,它不会影响正在创建的任何出价?
  5. 愿望清单:

    • 如果有可能,我想不要锁定整个投标表,因为无论如何都不会影响对其他产品的出价。
    • 如果在应用程序级别上有一个很好的解决方案,我想保持代码独立于底层数据库系统。

    非常感谢你的想法!

2 个答案:

答案 0 :(得分:0)

你签出了Celery吗?您可以异步处理查询,对查询进行排队,然后在结果或错误可用时将其返回。如果你想避免锁定,这似乎是一条可能的路径。

否则,似乎需要进行一些锁定。

答案 1 :(得分:0)

您是否可以向highest_bid添加Products列。如果我的逻辑没有关闭,您可以更新最高出价where product_id = x and highest < current_bid。如果此查询指示已更新行,则将新记录添加到出价表中。这可能意味着您必须拥有high_bid列的默认值。