如何确保所有事务都已提交或回滚?

时间:2018-12-19 14:31:08

标签: oracle plsql

我有一个PL / SQL过程,例如:

procedure MyProcedure() is 
begin 
    insert into table1 (field1, Field2) values ('value1','value2');

    -- do some staff

    insert into table2 (field1, Field2) values ('value1','value2');

    -- do some staff

    delete from table3 where id = xx;

    -- do some staff
end;

某些过程指令可能会失败,我希望所有指令之间保持一定的连贯性。这意味着,如果一条指令失败,我希望所有其他指令都回滚。所以要么全部执行,要么什么都不执行。

有人知道怎么做吗?

谢谢。

干杯

4 个答案:

答案 0 :(得分:1)

最后输入COMMIT;ROLLBACK;-就是这样。当然,仅当您之间没有任何命令执行隐式COMMIT时,您才会获得预期的行为,例如TRUNCATE TABLE ...

答案 1 :(得分:1)

如果发生任何错误并回滚,则可以引发异常;如果没有发生错误,则可以添加提交。 请注意,如果将来添加任何DDL语句(create,alter),则将提交该语句。

BEGIN

insert into table1 (field1, Field2) values ('value1','value2');

-- do some staff

insert into table2 (field1, Field2) values ('value1','value2');

-- do some staff

delete from table3 where id = xx;
commit;
  -- if any error occured
   WHEN OTHERS THEN  
 rollback;
END; 
/

答案 2 :(得分:1)

事务控制最好应该在调用它的地方而不是在过程内部进行,除非它是一个自主事务。

procedure MyProcedure( ret_status out int ) is
..
..

调用(可能是其他过程/块或Web应用程序)

DECLARE
     v_ret_status   INTEGER;
BEGIN
     myprocedure(v_ret_status);
     IF
          v_ret_status = 0
     THEN
          COMMIT;
     ELSE
          ROLLBACK;
     END IF;
END;
/

此外,最好在异常部分中调用日志记录过程或带有相关错误消息的dbms_output

答案 3 :(得分:0)

您所要求的或多或少是默认行为:

create table test1 (id integer not null);
create table test2 (id integer not null);
create table test3 (id integer not null);

create or replace procedure myProcedure
    ( p1 test1.id%type
    , p2 test2.id%type
    , p3 test3.id%type )
as
begin
    insert into test1 (id) values (p1);
    insert into test2 (id) values (p2);
    insert into test3 (id) values (p3);
end myProcedure;
/

call myProcedure(1, 2, 3);
-- completes successfully

call myProcedure(1, 2, null);
-- fails with:
-- ERROR at line 1:
-- ORA-01400: cannot insert NULL into ("WILLIAM"."TEST3"."ID")
-- ORA-06512: at "WILLIAM.MYPROCEDURE", line 9

select 'test1' as table_name, test1.id from test1 union all
select 'test2', test2.id from test2 union all
select 'test3', test3.id from test3
order by 1;

TABLE         ID
----- ----------
test1          1
test2          2
test3          3

3 rows selected.

因此,在调用没有成功的情况下,我只有三行,而在失败的调用中没有任何行,所有这些都没有明确地提交或回滚。

如果您确实要提交commit,则可以在过程的末尾添加begin delete test1; delete test2; delete test3; myProcedure(1, 2, null); exception when others then dbms_output.put_line(sqlerrm); dbms_output.put_line(dbms_utility.format_error_backtrace); end; ORA-01400: cannot insert NULL into ("WILLIAM"."TEST3"."ID") ORA-06512: at "WILLIAM.MYPROCEDURE", line 9 ORA-06512: at line 6 PL/SQL procedure successfully completed. (并非总是一个好主意,但要求会有所不同)。

但是,仅当异常一直传播到调用方时,才会发生默认的“回滚到隐式保存点”行为,例如,如果我尝试使用以下方式处理它:

select 'test1' as table_name, test1.id from test1 union all
select 'test2', test2.id from test2 union all
select 'test3', test3.id from test3
order by 1;

TABLE         ID
----- ----------
test1          1
test2          2

2 rows selected.

现在,由于该块已成功完成,因此我获得了运行中部分失败的值:

create or replace procedure myProcedure
    ( p1 test1.id%type
    , p2 test2.id%type
    , p3 test3.id%type )
as
begin
    savepoint start_of_processing;

    insert into test1 (id) values (p1);
    insert into test2 (id) values (p2);
    insert into test3 (id) values (p3);

    commit;
exception
    when others then
        rollback to start_of_processing;
        -- Log using whatever logging package you have:
        logger.message('Something appears to have gone disastrously amiss');
        raise;
end myProcedure;

无论如何,要明确处理所有这些,您可能需要这样的东西:

{{1}}

请记住,the act of observing an exception changes it irrevocably。据我所知,在所有编程语言中都是如此。