[英]Firebird 2.5 commit/rollback (using autonomous transaction) in loop
我必須在存儲過程的循環中處理記錄,例如:
create or alter procedure process_waiting_records
as
declare v_id type of column my_table.id;
begin
for
select
t.id
from
my_table t
where
(t.status = 'WAITING_TO_PROCESS')
order by
t.created_at
into
:v_id
do
begin
execute procedure process_one_record(:v_id);
end
end ^
問題是當process_one_record()
的執行失敗(產生任何類型的異常)時,整個修改集將從調用代碼回滾。
目標是處理所有可能的記錄,如果某些記錄無法處理,我現在並不關心,這些失敗的記錄無論如何都會記錄在日志表中(使用自治事務)。
我正在考慮在一個自治事務塊中調用process_one_record()
存儲過程,使用when any do (dummy code)
子句。 但是,我認為這是行不通的,因為失敗的事務不會被回滾,而是被提交(參考這個主題: Firebird 2.5 自治事務中的異常處理)。
有人可以指出我如何解決這個問題的正確方向嗎?
為此,您不需要匿名交易。 當存儲過程拋出異常時,該存儲過程的影響將自動撤消。 如果存儲過程包含SUSPEND
,則只有直到最后一個SUSPEND
的效果才會被撤消(將其視為保存點)。 對於任何其他形式的回滾,需要顯式回滾事務。
另請參閱 Firebird 2.5 語言參考中的保存點和 PSQL 。
PSQL 中不允許使用事務控制語句,因為這會破壞調用過程的語句的原子性。 但是,Firebird 確實支持在 PSQL 中引發和處理異常,因此可以有選擇地撤消在存儲過程和觸發器中執行的操作,而不會導致整個過程失敗。
在內部,自動保存點用於:
- 撤消發生異常的
BEGIN...END
塊中的所有操作- 撤消過程或觸發器執行的所有操作,或者,對於可選過程,自上次 SUSPEND 以來執行的所有操作,當執行因未捕獲的錯誤或異常而提前終止時
每個 PSQL 異常處理塊也受自動系統保存點的限制。
注意:
BEGIN...END
塊本身不會創建自動保存點。 保存點僅在包含用於處理異常的 WHEN 語句的塊中創建。
在這種情況下,由於需要撤消單個process_one_record
的影響,而不是process_waiting_records
的整個處理,因此您需要允許將異常從process_one_record
拋出,但要為該單個過程調用捕獲它。
簡而言之,您需要執行以下操作:
for select
...
do
begin
execute procedure process_one_record(:v_id);
when any do
begin
-- do nothing, last call to `process_one_record` was undone
end
end
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.