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