我正在使用
Django==2.2
并尝试仅在未达到上限时为 django 中的对象创建一些新记录。我正在检查
unused_count = Account.objects.filter(field1__isnull=True, field2__isnull=True).count()
vacancies = UPPER_LIMIT - unused_count
if vacancies > 0:
*create (vacancies) new accounts here*
但是,我们遇到了这样的情况:这一点没有得到尊重,并且创建的最大限制帐户增加了一倍,这很可能看起来像是并发问题。
只是想确认使用
unused_count = Account.objects.select_for_update().filter(field1__isnull=True, field2__isnull=True).count()
是否足以避免这个问题?
整个方法被包裹在
@transaction.atomic
假设您实际上使用的是支持
SELECT ... FOR UPDATE
的数据库,我认为问题在于count()
评估查询集。
根据文档(https://docs.djangoproject.com/en/4.2/ref/models/querysets/#select-for-update)
select_for_update
应该用于返回一个查询集,然后对其进行迭代在原子事务中。
您没有这样做,而是使用
count
立即评估查询集。即使整个事情都包含在 transaction.atomic
中,我认为这可能是你的问题 - 因为 qs 是立即评估的,然后另一个会话可以出现并选择相同的记录,这意味着你有 2 件事在做同样的事情同时,这就是你如何设法获得太多记录的原因。
我不是 100% 确定这会起作用,但试试这个......
unused_qs = Account.objects.filter(field1__isnull=True, field2__isnull=True)
with transaction.atomic():
if UPPER_LIMIT - unused_qs.count() > 0:
*create (vacancies) new accounts here*
这将 qs 的评估与记录创建一起放入原子事务中。
(如果这不起作用,请告诉我,我会根据发生的情况删除或完善此答案......)