W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
從第 43.8 節(jié)中介紹的數(shù)據(jù)庫訪問導(dǎo)致的錯誤中恢復(fù)可能導(dǎo)致一種不可取的情況,其中一些操作在它們中的一個失敗前成功完成,并且在從錯誤中恢復(fù)過來后數(shù)據(jù)還處于一種不一致的狀態(tài)。PL/Tcl以顯式子事務(wù)的形式為這類問題提供了一個解決方案。
考慮一個在兩個賬戶間實現(xiàn)轉(zhuǎn)賬的函數(shù):
CREATE FUNCTION transfer_funds() RETURNS void AS $$
if [catch {
spi_exec "UPDATE accounts SET balance = balance - 100 WHERE account_name = 'joe'"
spi_exec "UPDATE accounts SET balance = balance + 100 WHERE account_name = 'mary'"
} errormsg] {
set result [format "error transferring funds: %s" $errormsg]
} else {
set result "funds transferred successfully"
}
spi_exec "INSERT INTO operations (result) VALUES ('[quote $result]')"
$$ LANGUAGE pltcl;
如果第二個UPDATE
語句導(dǎo)致一個異常,這個函數(shù)將記下該失敗,但是第一個UPDATE
的結(jié)果將被提交。換句話說,資金將從Joe的賬戶中被取走,但不會被轉(zhuǎn)到Mary的賬戶。這是因為每個spi_exec
都是一個單獨的子事務(wù),并且那些子事務(wù)中只有一個被回滾。
為了處理這類情況,你可以把多個數(shù)據(jù)庫操作包裹在一個顯式子事務(wù)中,它將作為一個整體成功完成或者回滾。PL/Tcl提供了一個subtransaction
命令來做這件事情。我們可以把我們的函數(shù)寫成:
CREATE FUNCTION transfer_funds2() RETURNS void AS $$
if [catch {
subtransaction {
spi_exec "UPDATE accounts SET balance = balance - 100 WHERE account_name = 'joe'"
spi_exec "UPDATE accounts SET balance = balance + 100 WHERE account_name = 'mary'"
}
} errormsg] {
set result [format "error transferring funds: %s" $errormsg]
} else {
set result "funds transferred successfully"
}
spi_exec "INSERT INTO operations (result) VALUES ('[quote $result]')"
$$ LANGUAGE pltcl;
注意,為了實現(xiàn)這個目的仍要求使用catch
。否則錯誤將傳播到該函數(shù)的頂層,導(dǎo)致想要對operations
表的插入被阻止。subtransaction
命令不會捕捉錯誤,它僅確保報告錯誤時在其范圍內(nèi)執(zhí)行的所有數(shù)據(jù)庫操作將被一起回滾。
一個顯式子事務(wù)的回滾發(fā)生在包含它的Tcl代碼報告任何錯誤時,而不僅僅是數(shù)據(jù)庫訪問導(dǎo)致的錯誤。因此一個subtransaction
命令中發(fā)生的常規(guī)Tcl異常也將導(dǎo)致該子事務(wù)被回滾。不過,無錯誤退出到包含子事務(wù)的Tcl代碼外面(例如,由于return
)不會導(dǎo)致回滾。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: