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