我有以下模型,即使我在聚合中使用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对象?