在Oracle上回滚@存储过程

时间:2010-08-16 02:54:23

标签: oracle stored-procedures transactions rollback

我不知道这是否正确但由于某种原因我的存储过程在发生异常后没有回滚。所以即使我得到异常

,我的insert语句也会被提交

我忘记了什么吗?

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 个答案:

答案 0 :(得分:5)

“EXECUTE IMMEDIATE sCreateUser;”隐含地提交你的插入。

答案 1 :(得分:1)

我怀疑你正在“处理”(或更准确地说,忽略)你的例外。

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层而言,该过程已成功完成(因为异常被捕获并被忽略)。

可能还有其他原因,例如

  • 插入在程序执行之前发生,因此在语句失败时不会回滚(并且您没有显式回滚事务)
  • 在引发异常之前,通过显式提交提交插入。

答案 2 :(得分:0)

我认为如果您重构代码,就可以获得所需的行为。

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;   

答案 3 :(得分:0)

RAISE_APPLICATION_ERROR是否意味着ROLLBACK无法访问?除非调用者也发出ROLLBACK,否则我认为那些需要反过来。你可能正在接受DDL的隐式提交,正如其他人所说,取决于实际上是错误的,所以它可能是无关紧要的,但它看起来不太正确。