以并发安全的方式删除Django查询集

h43kikqp  于 2023-05-23  发布在  Go
关注(0)|答案(1)|浏览(174)

我想以并发安全的方式删除数量为零的行。可以想象的是,该行在即将被删除之前可能变为非零。
模型看起来像这样:

class Stock(models.Model):
   product = models.ForeignKey(Product)
   location = models.ForeignKey(Location)
   quantity = models.IntegerField()

要删除它,我使用:

Stock.objects.filter(product=product, quantity=0).delete()

我希望SQL是:

DELETE FROM app_stock WHERE product=product AND quantity=0

但它正在进行优化,以:

DELETE FROM "app_stock" WHERE "app_stock"."id" IN (5)

这种优化在某种意义上是非常合理的,因为要删除的对象的ID是5,这是更有效的。不幸的是,这将是不安全的,因为股票可能会增加另一个过程在任何时候。
我可以用原始SQL解决这个问题。我也尝试过其他查询,但它总是以同样的方式优化。

7d7tgy0s

7d7tgy0s1#

这种优化在某种意义上是非常合理的,因为要删除的对象的ID是5,这是更有效的。

,这不是出于性能原因,特别是为了首先知道主键是什么,Django执行另一个查询。因此,为了删除,至少进行两次查询。

发生这种情况的原因是因为Django本身执行on_delete=…查询。因此,它首先需要将被移除的对象,并且如果存在ForeignKey s等。它还将获取指向这些对象的相关查询集以相应地执行触发器。通过手动执行触发器,在单个查询中(几乎)不可能做到这一点。
最好的办法可能是将这些内容 Package 在 transactions 中,这样最终的删除是原子地完成的:它要么完全成功,要么根本不成功。

相关问题