Откат @ Хранимая процедура в Oracle - PullRequest
4 голосов
/ 16 августа 2010

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

Я что-то забыл?

PROCEDURE SP_USUARIO_INSERT
        (
          pUSU_IDUSUARIO          IN OUT ENG.USU_USUARIO.USU_IDUSUARIO%TYPE,
          pUSU_CDUSUARIO          IN ENG.USU_USUARIO.USU_CDUSUARIO%TYPE,
          pPES_IDPESSOA           IN ENG.USU_USUARIO.PES_IDPESSOA%TYPE,
          pUSU_DLSENHA            IN ENG.USU_USUARIO.USU_CDUSUARIO%TYPE,
          pUSU_DLOBSERVACAO       IN ENG.USU_USUARIO.USU_DLOBSERVACAO%TYPE,
          pUSU_NUIP               IN ENG.USU_USUARIO.USU_NUIP%TYPE,
          pUSU_DTCADASTRO         IN ENG.USU_USUARIO.USU_DTCADASTRO%TYPE,
          pUSU_DTDESATIVACAO      IN ENG.USU_USUARIO.USU_DTDESATIVACAO%TYPE,
          pUSU_DTULTIMOACESSO     IN ENG.USU_USUARIO.USU_DTULTIMOACESSO%TYPE,
          pUSU_DLMAQUINA          IN ENG.USU_USUARIO.USU_DLMAQUINA%TYPE,
          pUSU_STNOVO             IN ENG.USU_USUARIO.USU_STNOVO%TYPE,
          pUSU_STATIVO            IN ENG.USU_USUARIO.USU_STATIVO%TYPE
        )
IS
sCreateUser Varchar(200);
bUsuarioExiste Number;
eUsuarioExiste Exception;
BEGIN
       SELECT 
               COUNT(usu_cdusuario) 
               INTO bUsuarioExiste 
        FROM ENG.USU_USUARIO 
        WHERE USU_CDUSUARIO = pUSU_CDUSUARIO;

        IF(bUsuarioExiste > 0) THEN
              RAISE eUsuarioExiste;
        END IF;

        SELECT usu_seq.nextval INTO pUSU_IDUSUARIO FROM DUAL;

        INSERT INTO ENG.USU_USUARIO
             (
                USU_IDUSUARIO, 
                USU_CDUSUARIO, 
                PES_IDPESSOA, 
                USU_DLOBSERVACAO, 
                USU_NUIP, 
                USU_DTCADASTRO, 
                USU_DTDESATIVACAO, 
                USU_DTULTIMOACESSO, 
                USU_DLMAQUINA, 
                USU_STNOVO, 
                USU_STATIVO
             )
        VALUES
             (
                pUSU_IDUSUARIO, 
                pUSU_CDUSUARIO, 
                pPES_IDPESSOA, 
                pUSU_DLOBSERVACAO, 
                pUSU_NUIP, 
                sysdate, 
                pUSU_DTDESATIVACAO, 
                pUSU_DTULTIMOACESSO, 
                pUSU_DLMAQUINA, 
                pUSU_STNOVO, 
                pUSU_STATIVO 
             ) ;
        sCreateUser := 'CREATE USER ' || pUSU_CDUSUARIO || ' IDENTIFIED BY ' || pUSU_DLSENHA;
        EXECUTE IMMEDIATE sCreateUser;
        EXECUTE IMMEDIATE 'GRANT ENG_GERAL TO ' || pUSU_CDUSUARIO;
        COMMIT;
EXCEPTION
       WHEN eUsuarioExiste THEN
             RAISE_APPLICATION_ERROR (-20001, 'Usuário já existe ou possui nome inválido.');
             ROLLBACK;
       WHEN OTHERS THEN
             RAISE_APPLICATION_ERROR (-20001, SQLCODE || ': ' || SQLERRM);
             ROLLBACK;
END SP_USUARIO_INSERT;

Ответы [ 4 ]

5 голосов
/ 16 августа 2010

«ВЫПОЛНИТЬ НЕМЕДЛЕННЫЙ sCreateUser;»неявно фиксирует вашу вставку.

1 голос
/ 16 августа 2010

Я подозреваю, что вы обрабатываете (или, точнее, игнорируете) свое исключение.

create table temp (id number);
DECLARE
  v_str VARCHAR2(2);
BEGIN
  INSERT INTO temp VALUES (1);
  v_str := '123';
EXCEPTION
  WHEN VALUE_ERROR THEN DBMS_OUTPUT.PUT_LINE('Whoops');
END;
/
select * from temp;

Покажет строку, поскольку, что касается уровня SQL, процедура завершилась успешно (исключение было перехвачено и проигнорировано).

Могут быть и другие причины, например

.
  • Вставка происходит перед выполнением процедуры и поэтому не откатывается при сбое оператора (и вы не выполняете явный откат транзакции)
  • Вставка фиксируется явным подтверждением до возникновения исключения.
0 голосов
/ 20 августа 2010

Не означает ли RAISE_APPLICATION_ERROR, что ROLLBACK недоступен? Если вызывающая сторона также не выдает ROLLBACK, я думаю, что они должны быть наоборот. Вы можете получать неявную фиксацию от DDL, как говорили другие, в зависимости от того, что на самом деле дает ошибку, поэтому это может быть неактуально, но выглядит не совсем правильно.

0 голосов
/ 16 августа 2010

Я думаю, что если вы реструктурируете свой код, вы можете получить желаемое поведение.

PROCEDURE SP_USUARIO_INSERT      
        (      
          pUSU_IDUSUARIO          IN OUT ENG.USU_USUARIO.USU_IDUSUARIO%TYPE,      
          pUSU_CDUSUARIO          IN ENG.USU_USUARIO.USU_CDUSUARIO%TYPE,      
          pPES_IDPESSOA           IN ENG.USU_USUARIO.PES_IDPESSOA%TYPE,      
          pUSU_DLSENHA            IN ENG.USU_USUARIO.USU_CDUSUARIO%TYPE,      
          pUSU_DLOBSERVACAO       IN ENG.USU_USUARIO.USU_DLOBSERVACAO%TYPE,      
          pUSU_NUIP               IN ENG.USU_USUARIO.USU_NUIP%TYPE,      
          pUSU_DTCADASTRO         IN ENG.USU_USUARIO.USU_DTCADASTRO%TYPE,      
          pUSU_DTDESATIVACAO      IN ENG.USU_USUARIO.USU_DTDESATIVACAO%TYPE,      
          pUSU_DTULTIMOACESSO     IN ENG.USU_USUARIO.USU_DTULTIMOACESSO%TYPE,      
          pUSU_DLMAQUINA          IN ENG.USU_USUARIO.USU_DLMAQUINA%TYPE,      
          pUSU_STNOVO             IN ENG.USU_USUARIO.USU_STNOVO%TYPE,      
          pUSU_STATIVO            IN ENG.USU_USUARIO.USU_STATIVO%TYPE      
        )      
IS      
sCreateUser Varchar(200);      
bUsuarioExiste Number;      
eUsuarioExiste Exception;      
l_sqlcode      number;
BEGIN      
       SELECT       
               COUNT(usu_cdusuario)       
               INTO bUsuarioExiste       
        FROM ENG.USU_USUARIO       
        WHERE USU_CDUSUARIO = pUSU_CDUSUARIO;      

        IF(bUsuarioExiste > 0) THEN      
              RAISE eUsuarioExiste;      
        END IF;      

        sCreateUser := 'CREATE USER ' || pUSU_CDUSUARIO || ' IDENTIFIED BY ' ||     
                       pUSU_DLSENHA;      
        EXECUTE IMMEDIATE sCreateUser;      

        begin
              EXECUTE IMMEDIATE 'GRANT ENG_GERAL TO ' || pUSU_CDUSUARIO;      

              -- moved this into the insert          
              --SELECT usu_seq.nextval INTO pUSU_IDUSUARIO FROM DUAL;      

              INSERT INTO ENG.USU_USUARIO      
              (      
                   USU_IDUSUARIO,       
                   USU_CDUSUARIO,       
                   PES_IDPESSOA,       
                   USU_DLOBSERVACAO,       
                   USU_NUIP,       
                   USU_DTCADASTRO,       
                   USU_DTDESATIVACAO,       
                   USU_DTULTIMOACESSO,       
                   USU_DLMAQUINA,       
                   USU_STNOVO,       
                   USU_STATIVO      
              )      
              VALUES      
              (      
                   usu_seq.nextval,  --pUSU_IDUSUARIO,       
                   pUSU_CDUSUARIO,       
                   pPES_IDPESSOA,       
                   pUSU_DLOBSERVACAO,       
                   pUSU_NUIP,       
                   sysdate,       
                   pUSU_DTDESATIVACAO,       
                   pUSU_DTULTIMOACESSO,       
                   pUSU_DLMAQUINA,       
                   pUSU_STNOVO,       
                   pUSU_STATIVO       
              ) 
              returning ;      
        exception
          when others then 
             -- save off the sqlcode, you will need it to reraise
             l_sqlcode := SQLCODE;
             -- rollback any insert that may have run, 
             -- depending on where the exception was raised
             rollback;
             -- drop the created user
             execute immediate 'drop user ' || pUSU_CDUSUARIO ;
             -- reraise the error
             RAISE_APPLICATION_ERROR (-20001, l_sqlcode || ': ' || 
                                      SQLERRM(-l_sqlcode));                   
        end;

        COMMIT;      
EXCEPTION      
       WHEN eUsuarioExiste THEN      
             RAISE_APPLICATION_ERROR (-20001, 
                         'Usuário já existe ou possui nome inválido.');      
             ROLLBACK;      
       WHEN OTHERS THEN      
             RAISE_APPLICATION_ERROR (-20001, 
                 SQLCODE || ': ' || SQLERRM);      
             ROLLBACK;      
END SP_USUARIO_INSERT;   
...