当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Python Django QuerySet.select_for_update用法及代码示例


本文介绍 django.db.models.query.QuerySet.select_for_update 的用法。

声明

select_for_update(nowait=False, skip_locked=False, of=(), no_key=False)

返回一个查询集,它将锁定行直到事务结束,在支持的数据库上生成 SELECT ... FOR UPDATE SQL 语句。

例如:

from django.db import transaction

entries = Entry.objects.select_for_update().filter(author=request.user)
with transaction.atomic():
    for entry in entries:
        ...

当查询集被评估时(在这种情况下为for entry in entries),所有匹配的条目将被锁定直到事务块结束,这意味着其他事务将被阻止更改或获取它们的锁。

通常,如果另一个事务已经在其中一个选定的行上获得了锁,则查询将阻塞,直到锁被释放。如果这不是您想要的行为,请调用 select_for_update(nowait=True) 。这将使调用非阻塞。如果另一个事务已经获取了冲突锁,则在评估查询集时将引发 DatabaseError 。您也可以改用select_for_update(skip_locked=True) 来忽略锁定的行。 nowaitskip_locked 是互斥的,在启用这两个选项的情况下尝试调用 select_for_update() 将导致 ValueError

默认情况下,select_for_update() 锁定查询选择的所有行。例如,除了查询集模型的行之外, select_related() 中指定的相关对象的行也被锁定。如果不需要,请使用与 select_related() 相同的字段语法在 select_for_update(of=(...)) 中指定要锁定的相关对象。使用值 'self' 来引用查询集的模型。

select_for_update(of=(...)) 中锁定父模型

如果要在使用 multi-table 继承时锁定父模型,则必须在 of 参数中指定父链接字段(默认为 <parent_model_name>_ptr )。例如:

Restaurant.objects.select_for_update(of=('self', 'place_ptr'))

使用带有指定字段的select_for_update(of=(...))

如果您想锁定模型并指定选定的字段,例如使用 values() ,您必须从 of 参数中的每个模型中选择至少一个字段。没有选定字段的模型将不会被锁定。

仅在 PostgreSQL 上,您可以传递 no_key=True 以获得较弱的锁,这仍然允许创建仅引用锁定行的行(例如,通过外键),而锁到位。 PostgreSQL 文档包含有关 row-level lock modes 的更多详细信息。

您不能在可为空的关系上使用select_for_update()

>>> Person.objects.select_related('hometown').select_for_update()
Traceback (most recent call last):
...
django.db.utils.NotSupportedError: FOR UPDATE cannot be applied to the nullable side of an outer join

为了避免这种限制,如果你不关心它们,你可以排除空对象:

>>> Person.objects.select_related('hometown').select_for_update().exclude(hometown=None)
<QuerySet [<Person: ...)>, ...]>

postgresqloraclemysql 数据库后端支持 select_for_update() 。但是,MariaDB 10.3+ 仅支持nowait 参数,MariaDB 10.6+ 也支持skip_locked 参数,而MySQL 8.0.1+ 支持nowaitskip_lockedof参数。 no_key 参数仅在 PostgreSQL 上受支持。

使用不支持这些选项的数据库后端(例如 MySQL)将 nowait=Trueskip_locked=Trueno_key=Trueof 传递给 select_for_update() 会引发 NotSupportedError 。这可以防止代码意外阻塞。

在支持 SELECT ... FOR UPDATE 的后端上以自动提交模式使用 select_for_update() 评估查询集是 TransactionManagementError 错误,因为在这种情况下行没有被锁定。如果允许,这将促进数据损坏,并且很容易由调用期望在事务之外的事务中运行的代码引起。

在不支持 SELECT ... FOR UPDATE(例如 SQLite)的后端上使用 select_for_update() 将无效。 SELECT ... FOR UPDATE 不会添加到查询中,如果在自动提交模式下使用 select_for_update() 也不会引发错误。

警告

尽管 select_for_update() 通常在自动提交模式下失败,但由于 TestCase 自动将每个测试包装在事务中,因此即使在 atomic() 块之外调用 TestCase 中的 select_for_update() 也会(可能出乎意料地)通过而不会引发 TransactionManagementError .要正确测试 select_for_update() 您应该使用 TransactionTestCase

可能不支持某些表达式

PostgreSQL 不支持带有 Window 表达式的 select_for_update()

在 Django 3.2 中更改:

添加了no_key 参数。

MySQL 8.0.1+ 上允许使用 of 参数。

在 Django 4.0 中更改:

MariaDB 10.6+ 上允许使用 skip_locked 参数。

相关用法


注:本文由纯净天空筛选整理自djangoproject.com大神的英文原创作品 django.db.models.query.QuerySet.select_for_update。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。