Sql Firebird 2.5在循环中提交/回滚(使用自治事务)

Sql Firebird 2.5在循环中提交/回滚(使用自治事务),sql,firebird,firebird-psql,Sql,Firebird,Firebird Psql,我必须处理存储过程循环中的记录,例如: 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') ord

我必须处理存储过程循环中的记录,例如:

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\u one\u record()
失败(生成任何类型的异常)时,整个修改集将从调用代码回滚

我们的目标是处理所有可能的记录,此时我并不关心某些记录是否无法处理,这些失败的记录将被记录在日志表中(使用自治事务)

我正考虑在一个自治事务块中调用
process\u one\u record()
存储过程,同时使用
when any do(伪代码)
子句。但是,我认为这是行不通的,因为失败的事务将不会回滚,而是提交(参考此主题:)


有人能告诉我解决这个问题的正确方向吗?

你不需要匿名交易。当从存储过程中抛出异常时,该存储过程的效果将自动撤消。如果存储过程包含
SUSPEND
,则仅撤消上次
SUSPEND
之前的效果(将其视为保存点)。对于任何其他形式的回滚,都需要显式回滚事务

另请参见Firebird 2.5语言参考中的

在PSQL中不允许使用事务控制语句,这将 中断调用过程的语句的原子性。 但是,Firebird确实支持异常的引发和处理 在PSQL中,以便在存储过程和触发器中执行操作 可以有选择地撤消,而不会使整个过程失败

在内部,自动保存点用于:

  • 撤消出现异常的
    BEGIN…END
    块中的所有操作
  • 撤消程序或触发器执行的所有操作,或者对于可选程序,撤消自上次挂起以来执行的所有操作, 当执行因未捕获的错误或错误而提前终止时 例外情况
每个PSQL异常处理块也由自动系统绑定 保存点

注意:
BEGIN…END
块本身不会创建自动 保存点。保存点仅在包含WHEN的块中创建 用于处理异常的语句

在这种情况下,由于需要撤消单个
进程\单\记录
的影响,而不是
进程\等待\记录
中的整个处理,因此您需要允许从
进程\单\记录
中抛出异常,但为该单个过程调用捕获它

简而言之,您需要执行以下操作:

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

因此,如果我正确理解您使用这种方法所做的所有由失败的进程\u one\u record()所做的更改都将自动回滚(根本不涉及挂起),但是以前成功的进程\u one\u record()调用仍然可以在进程结束时提交\u waiting\u records?@tcxbalage Yes,只有对
process\u one\u record
的失败调用中的工作被撤消,其余工作被保留并可以提交。请注意,您实际上也可以在
进程\u one_记录
中捕获异常,在块中捕获异常会触发该块中所做工作的回滚,但是让异常从存储过程中出来并在调用方中处理它更干净。我完全没有注意到这一点“Savepoints and PSQL”lang.ref.我一直在寻找的是异常处理。我应该更彻底地做我的研究。谢谢你的帮助!