Django:在聚合期间避免竞争条件(SUM)

时间:2018-02-23 03:08:04

标签: django database concurrency race-condition

我有以下模型,即使我在聚合中使用select_for_update,我仍然遇到此withdraw方法中的竞争条件:

如何在entries方法完成之前锁定withdraw()

class BalanceHandler():
    @atomic
    def withdraw(account, amount):
        # race condition happened here where multiple withdrawals happenning concurrently
        # can't use entries.select_for_update().get_total() because it's not available for QuerySet
        if account.entries.get_total() < amount:
            raise Exception("not enough balance")            
         # do something with the amount


 class LedgerEntry(models.Model):
    amount = models.DecimalField(max_digits=18, decimal_places=6)
    ledger_account = models.ForeignKey(LedgerAccount, related_name='entries')

class LedgerEntryManager(models.Manager):
    def get_total(account, *args, **kwargs):
        return self.select_for_update().filter(*args, **kwargs).aggregate(Sum('amount'))['amount__sum']

class LedgerAccount(models.Model):
    account_number = models.CharField(max_length=20, editable=False)

注意:我发现了这个问题(How to prevent race condition in Django on INSERT with limiting SUM?),但在这种情况下,OP能够锁定主对象(项目)。就我而言,如何在withdraw()get_total()期间锁定LedgerAccount对象?

0 个答案:

没有答案