Как убедиться, что все транзакции либо зафиксированы, либо откатаны? - PullRequest
0 голосов
/ 19 декабря 2018

У меня есть процедура 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 голосов
/ 19 декабря 2018

То, что вы запрашиваете, является более или менее стандартным поведением:

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;

Имейте в виду, однако, что акт наблюдения исключения меняет его безвозвратно .Насколько я знаю, это верно для всех языков программирования.

0 голосов
/ 19 декабря 2018

вы можете вызвать исключение, если произойдет какая-либо ошибка, и откат, если ошибки не произошло, вы можете добавить коммит.Обратите внимание, что если в будущем вы добавите какие-либо операторы DDL (создайте, измените), операторы будут зафиксированы.

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; 
/
0 голосов
/ 19 декабря 2018

Управление транзакцией предпочтительно должно происходить там, где она вызывается, а не внутри процедуры, если только это не автономная транзакция.

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

Вызов (Может быть другая процедура / блок или веб-приложение)

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

Также предпочтительно вызывать процедуру регистрации или dbms_output с соответствующим сообщением об ошибке в разделе исключений.

0 голосов
/ 19 декабря 2018

В конце сделайте либо COMMIT;, либо ROLLBACK; - и все.Конечно, вы получите намеченное поведение, только если между ними нет команды, которая выполняет неявный COMMIT, например, TRUNCATE TABLE ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...