本文介绍 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。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。
