本文介绍 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)
来忽略锁定的行。 nowait
和 skip_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: ...)>, ...]>
postgresql
、 oracle
和 mysql
数据库后端支持 select_for_update()
。但是,MariaDB 10.3+ 仅支持nowait
参数,MariaDB 10.6+ 也支持skip_locked
参数,而MySQL 8.0.1+ 支持nowait
、skip_locked
和of
参数。 no_key
参数仅在 PostgreSQL 上受支持。
使用不支持这些选项的数据库后端(例如 MySQL)将 nowait=True
、 skip_locked=True
、 no_key=True
或 of
传递给 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()
。
添加了no_key
参数。
MySQL 8.0.1+ 上允许使用 of
参数。
MariaDB 10.6+ 上允许使用 skip_locked
参数。
相关用法
- Python Django QuerySet.select_related用法及代码示例
- Python Django QuerySet.union用法及代码示例
- Python Django QuerySet.latest用法及代码示例
- Python Django QuerySet.values用法及代码示例
- Python Django QuerySet.intersection用法及代码示例
- Python Django QuerySet.get用法及代码示例
- Python Django QuerySet.none用法及代码示例
- Python Django QuerySet.exclude用法及代码示例
- Python Django QuerySet.get_or_create用法及代码示例
- Python Django QuerySet.update_or_create用法及代码示例
- Python Django QuerySet.prefetch_related用法及代码示例
- Python Django QuerySet.first用法及代码示例
- Python Django QuerySet.annotate用法及代码示例
- Python Django QuerySet.dates用法及代码示例
- Python Django QuerySet.values_list用法及代码示例
- Python Django QuerySet.order_by用法及代码示例
- Python Django QuerySet.bulk_update用法及代码示例
- Python Django QuerySet.in_bulk用法及代码示例
- Python Django QuerySet.defer用法及代码示例
- Python Django QuerySet.aggregate用法及代码示例
- Python Django QuerySet.reverse用法及代码示例
- Python Django QuerySet.count用法及代码示例
- Python Django QuerySet.exists用法及代码示例
- Python Django QuerySet.explain用法及代码示例
- Python Django QuerySet.create用法及代码示例
注:本文由纯净天空筛选整理自djangoproject.com大神的英文原创作品 django.db.models.query.QuerySet.select_for_update。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。