當前位置: 首頁>>編程示例 >>用法及示例精選 >>正文


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