【问题标题】:Rollback @ Stored Procedure on OracleOracle 上的回滚@存储过程
【发布时间】:2010-08-16 02:54:23
【问题描述】:

我不知道这是否正确,但由于某种原因,我的存储过程在发生异常后没有回滚。所以即使我遇到异常,我的插入语句也会被提交

我是不是忘记了什么?

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;

【问题讨论】:

  • 很难说没有看到你的代码
  • 可能在SP退出时执行了提交?请发布一些代码。描述问题的简短 sn-p 是可以的。
  • 您的存储过程是否执行任何 DDL?这将隐式提交任何未完成的 DML 语句。然而,没有代码,我们所做的只是猜测。
  • 我认为亚当很赚钱。 CREATE USER 是 DDL。

标签: oracle stored-procedures transactions rollback


【解决方案1】:

“立即执行 sCreateUser;”正在隐式提交您的插入。

【讨论】:

  • @alex:你是怎么解决这个问题的?
【解决方案2】:

我怀疑您正在“处理”(或更准确地说,忽略)您的异常。

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

可能还有其他原因,例如

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

【讨论】:

    【解决方案3】:

    我认为如果你重构你的代码,你可以得到你想要的行为。

    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;   
    

    【讨论】:

      【解决方案4】:

      RAISE_APPLICATION_ERROR 不是意味着ROLLBACK 无法访问吗?除非调用者也发出ROLLBACK,否则我认为这些需要反过来。正如其他人所说,您可能会从 DDL 获得隐式提交,具体取决于实际出错的内容,因此它可能无关紧要,但看起来不太正确。

      【讨论】:

        猜你喜欢
        • 2012-01-04
        • 2019-06-03
        • 2016-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-31
        • 2014-08-31
        • 1970-01-01
        相关资源
        最近更新 更多