【发布时间】:2011-06-08 22:10:26
【问题描述】:
我正在 Django 中实现一个拍卖玩具应用程序,并且对如何在下面的代码中最好地处理并发感到困惑。我不确定我的哪个解决方案候选者(或任何其他)最适合 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)
和出价视图。这是竞争条件发生的地方(参见 cmets):
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)'
目前我考虑过的候选解决方案:
- 我已阅读有关事务的 Django 文档,但我不知道如何将它们应用于我的问题。由于数据库不知道出价必须上升的要求,它不会导致 Django 抛出 IntegrityError。有没有办法在模型定义期间定义这个约束?还是对事务 API 有误解?
- 存储过程可以处理出价逻辑。在我看来,到目前为止,这似乎是“最佳”选择,但它将处理竞争条件转移到了底层数据库系统。不过,如果这是一个好方法,这个解决方案可能会与解决方案 1 结合使用吗?
- 我考虑使用 select_for_update 调用来锁定该产品的出价。但是,这似乎不是一个解决方案,因为据我了解,它不会影响正在创建的任何新出价?
愿望清单:
- 如果可能的话,我想避免锁定整个投标表,因为其他产品的投标无论如何都不会受到影响。
- 如果在应用层面有好的解决方案,我希望代码独立于底层数据库系统。
非常感谢您的想法!
【问题讨论】:
标签: django concurrency