本文介紹 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。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。