使用 django select_for_update 不更新而是创建新记录

问题描述 投票:0回答:1

我正在使用

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
python django django-models django-rest-framework transactions
1个回答
0
投票

假设您实际上使用的是支持

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 的评估与记录创建一起放入原子事务中。

(如果这不起作用,请告诉我,我会根据发生的情况删除或完善此答案......)

© www.soinside.com 2019 - 2024. All rights reserved.