发生异常时,使PL/SQL存储过程回滚所有更改?

And*_*ers 3 oracle plsql stored-procedures transactions rollback

我有一个程序,可以对不同的表进行大量更新.如果过程中的任何地方发生任何错误,我希望回滚所有更改.因此我利用了这个结构:

CREATE PROCEDURE foo (x NUMBER) IS
BEGIN
  -- Do some inserts here.
  INSERT INTO bar VALUES (x);
  -- Sometimes there might be an error.
  IF x = 3 THEN
    RAISE_APPLICATION_ERROR(-20000, 'Wooops...');
  END IF;
EXCEPTION
  WHEN OTHERS THEN
    --Rollback all the changes and then raise the error again.
    ROLLBACK;
    RAISE;
END foo;
Run Code Online (Sandbox Code Playgroud)

问题是,这会回滚自上次提交以来所做的所有事情,而不仅仅是过程所做的更改.例如,这将插入4和5,但1和2将回滚:

BEGIN
  FOR x IN 1..5 LOOP
    BEGIN
      foo(x);
    EXCEPTION
      WHEN OTHERS THEN
        NULL;
    END;
  END LOOP;
END;
Run Code Online (Sandbox Code Playgroud)

如何使程序仅回滚此过程中程序所做的更改?我想我应该以某种方式使用交易,但我不知道如何设置它.

请注意,我想在程序的代码中修复此问题,而不是在调用它的代码中修复此问题.

Wer*_*eit 9

在Oracle中,您可以使用SAVEPOINTS.就是这样:

CREATE PROCEDURE foo (x NUMBER) IS
BEGIN
  SAVEPOINT update_bar;

  -- Do some inserts here.
  INSERT INTO bar VALUES (x);
  -- Sometimes there might be an error.
  IF x = 3 THEN
    RAISE_APPLICATION_ERROR(-20000, 'Wooops...');
  END IF;
EXCEPTION
  WHEN OTHERS THEN
    -- Rollback everything which was made after `SAVEPOINT update_bar`
    ROLLBACK TO update_bar;
    RAISE;
END foo;
Run Code Online (Sandbox Code Playgroud)