W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
Django 默認的事務行為是自動提交。除非事務正在執(zhí)行,每個查詢將會馬上自動提交到數(shù)據(jù)庫。
Django 自動使用事務或還原點,以確保需多次查詢的 ORM 操作的一致性,特別是 ?delete()
? 和 ?update()
? 操作。
由于性能原因,Django 的 ?TestCase
? 類同樣將每個測試用事務封裝起來。
在 Web 里,處理事務比較常用的方式是將每個請求封裝在一個事務中。 在你想啟用該行為的數(shù)據(jù)庫中,把配置中的參數(shù) ?ATOMIC_REQUESTS
?設置為 ?True
?。
它是這樣工作的:在調(diào)用視圖方法前,Django 先生成一個事務。如果響應能正常生成,Django 會提交該事務。而如果視圖出現(xiàn)異常,Django 則會回滾該事務。
你可以在你的視圖代碼中使用還原點執(zhí)行子事務,一般會使用 ?atomic()
? 上下文管理器。但是,在視圖結(jié)束時,要么所有的更改都被提交,要么所有的更改都不被提交。
注意:雖然這種簡潔的事務模型很吸引人,但在流量增加時,也會降低效率。為每個視圖打開一個事務都會帶來一些開銷。對性能的影響程度取決于應用執(zhí)行的查詢語句和數(shù)據(jù)庫處理鎖的能力。
當視圖返回一個 ?StreamingHttpResponse
?時,獲取該響應的內(nèi)容總會執(zhí)行代碼,生成內(nèi)容。由于早就返回了該視圖,某些代碼會在事務外執(zhí)行。
一般來說,不建議在生成流式響應時寫入數(shù)據(jù)庫,因為在開始發(fā)送響應后,就沒有能有效處理錯誤的方法了。
實際上,此功能只是簡單地用下文介紹的 ?atomic()
? 裝飾器裝飾了每個視圖函數(shù)。
注意,只有視圖被限制在事務中執(zhí)行。中間件在事務之外運行,同理,渲染模板響應也是在事務之外運行的。
即便啟用了 ?ATOMIC_REQUESTS
?,仍能避免視圖在事務中運行。
該裝飾器會為指定視圖取消 ?ATOMIC_REQUESTS
?的影響。
from django.db import transaction
@transaction.non_atomic_requests
def my_view(request):
do_stuff()
@transaction.non_atomic_requests(using='other')
def my_other_view(request):
do_stuff_on_the_other_database()
只有在它被應用到視圖時才會生效。
Django 提供了一個 API 控制數(shù)據(jù)庫事務。
原子性是數(shù)據(jù)庫事務的定義屬性。 ?atomic
?允許創(chuàng)建代碼塊來保證數(shù)據(jù)庫的原子性。如果代碼塊成功創(chuàng)建,這個變動會提交到數(shù)據(jù)庫。如果有異常,變動會回滾。
?atomic
?塊可以嵌套。在這個例子里,當內(nèi)部塊成功完成時,如果在稍后外部塊里引發(fā)了異常,則仍可回滾到最初效果。
確保原子塊始終是最外層的原子塊有時很有用,確保在退出塊時提交任何數(shù)據(jù)庫更改而沒有錯誤。 這稱為持久性,可以通過設置?durable=True
?來實現(xiàn)。 如果原子塊嵌套在另一個塊中,則會引發(fā) ?RuntimeError
?。
atomic 既可用作裝飾器:
from django.db import transaction
@transaction.atomic
def viewfunc(request):
# This code executes inside a transaction.
do_stuff()
并作為上下文管理器:
from django.db import transaction
def viewfunc(request):
# This code executes in autocommit mode (Django's default).
do_stuff()
with transaction.atomic():
# This code executes inside a transaction.
do_more_stuff()
在 ?try
?/?except
?塊中使用裝飾器 ?atomic
?來允許自然處理完整性錯誤:
from django.db import IntegrityError, transaction
@transaction.atomic
def viewfunc(request):
create_parent()
try:
with transaction.atomic():
generate_relationships()
except IntegrityError:
handle_exception()
add_children()
在這個例子里,雖然 ?generate_relationships()
? 會通過破壞完整性約束導致數(shù)據(jù)庫錯誤,但你可以 ?add_children()
? 中執(zhí)行查找,來自 ?create_parent()
? 的變化也會在這里,并且綁定到相同的事務。注意,任何試圖在 ?generate_relationships()
? 中執(zhí)行的操作在 ?handle_exception()
? 被調(diào)用的時候也會安全的回滾,因此異常處理也會在必要的時候在數(shù)據(jù)庫上操作。
當存在 ?atomic
?塊時, Django 查看它是否正常退出或存在異常來決定是提交還是正常回滾。如果你在 ?atomic
?內(nèi)部捕捉并且處理異常,你可以對 Django 隱藏問題代碼。這會導致一些意外的行為。
這主要是 ?DatabaseError
?和它的子類的一個問題(比如 ?IntegrityError
?)。出現(xiàn)這樣的錯誤之后,事務會奔潰,并且 Django 將在 ?atomic
?塊的末尾執(zhí)行回滾。如果你打算在回滾發(fā)生的時候運行數(shù)據(jù)庫查詢,Django 將引發(fā) ?TransactionManagementError
?錯誤。當 ORM 相關的信號處理程序引發(fā)異常時,你也可能遇到這個問題。
捕捉數(shù)據(jù)庫錯誤的正確的方法是像上方所示那樣圍繞 ?atomic
?塊。如有需要,為此目的可以添加額外的 ?atomic
?塊。這個模式有別的優(yōu)勢:如果異常發(fā)生,它會明確界定哪些操作將回滾。
如果捕獲由原始SQL查詢引發(fā)的異常,那么Django的行為是未指定的,并且依賴于數(shù)據(jù)庫。
當事務回滾時,模型字段的值不會被恢復。除非你手工恢復初始的字段值,否則這會導致模型狀態(tài)不一致。
例如,給定帶有 ?active
?字段的 ?MyModel
?模型,如果在事務中更新 ?active
?到 ?True
?失敗,那么這個片段確保最后的 ?if obj.active
? 檢查使用正確的值:
from django.db import DatabaseError, transaction
obj = MyModel(active=False)
obj.active = True
try:
with transaction.atomic():
obj.save()
except DatabaseError:
obj.active = False
if obj.active:
...
為了保證原子性,?atomic
?禁用了一些API。在 ?atomic
?塊中試圖提交、回滾或改變數(shù)據(jù)庫連接的自動提交狀態(tài)將引發(fā)異常。
?atomic
?帶有 ?using
?參數(shù),這個參數(shù)是數(shù)據(jù)庫名字。如果這個參數(shù)沒有提供,Django 會使用默認數(shù)據(jù)庫。
在后臺,Django 的事務管理代碼:
atomic
塊時打開事務;atomic
?塊內(nèi)部時創(chuàng)建一個保存點;你可以通過設置 ?savepoint
?參數(shù)為 ?False
?來為內(nèi)部塊禁用保存點的創(chuàng)建。如果發(fā)生異常,Django將在退出帶有保存點的第一個父塊(如果有的話)時執(zhí)行回滾,否則退出最外面的塊。外部事物仍保證了原子性。僅當保存點開銷明顯時,才應使用此選項。它的缺點是破壞了上述錯誤處理。
當自動提交關閉時,可以使用 ?atomic
?。它將只使用保存點,即使對于最外面的塊也是如此。
打開事務會對數(shù)據(jù)庫服務器有性能成本。盡量減少這種開銷,要保持事務盡可能簡短。如果正在 Django 的請求 / 響應周期之外,在長時間運行的進程中使用 ?atomic()
? ,這點尤其重要。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: