2011-06-08 72 views
4

我在Django中實現了一個eauction玩具應用程序,並且對如何在下面的代碼中最好地處理併發性感到困惑。我不確定我的解決方案候選人(或任何其他人)對Django的設計最適合。我對Django/python相當陌生,而且我的SQL知識很生疏,所以如果這是一件不容易的事情,我很抱歉。在Django中處理併發的最佳方法eauction玩具-app

要求:用戶可以對產品進行出價。只有在投標高於之前對同一產品的投標時,投標才被接受。

這裏是模型的一個精簡版:

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. 我考慮使用select_for_update調用來鎖定此產品的出價。然而,這似乎並不是一個解決方案,因爲在我的理解中,它不會影響任何新的競價被創建?

願望清單:

  • 如果在任何可能的方式,我想從鎖定整個表中標不要,因爲其他產品的出價不能無論如何影響。
  • 如果在應用程序級別上有一個很好的解決方案,我想讓代碼獨立於底層的數據庫系統。

非常感謝您的想法!

回答

0

您是否已退房Celery?您可能會異步處理查詢,排隊查詢,然後在結果或錯誤可用時返回。如果你想避免鎖定,這似乎是一個可能的途徑。

否則,它看起來好像需要發生一些鎖定。

+0

我不知道芹菜。感謝你!如果我的應用程序不會是「玩具」(閱讀:小量的交易,..)我會考慮Celery肯定會實現可擴展性。 – Roland 2011-06-09 08:08:17

0

是否可以將highest_bid列添加到Products。如果我的邏輯沒有關閉,您可以更新最高出價where product_id = x and highest < current_bid。如果此查詢表明某行已更新,則您將新記錄添加到出價表中。這可能意味着您必須爲highest_bid列設置默認值。

+0

謝謝!這將做到這一點。它不僅限制了單行上的數據庫鎖定,而且還允許我擺脫醜陋的聚合函數,以計算上面示例代碼中當前的'highest_bid'。 – Roland 2011-06-09 08:03:06