【问题标题】:Oracle: Savepoints within execute immediate and ORA-01086Oracle:立即执行和 ORA-01086 中的保存点
【发布时间】:2018-04-26 07:58:05
【问题描述】:

有人知道,为什么我在以下代码中得到一个ORA-01086: savepoint 'SPX' never established in this session or is invalid

begin 
    rollback; --clear all Transactions
    execute immediate 'begin
                           savepoint SPX;
                           raise no_data_found;  
                       end;';
exception when no_data_found then 
    rollback to savepoint SPX;
end;

如果我不使用立即执行,它就可以工作:

begin 
    rollback; --clear all Transactions
    begin
        savepoint SPX;
        raise no_data_found;  
    end;
exception when no_data_found then 
    rollback to savepoint SPX;
end;

这是预期的行为还是类似于错误?

我正在使用Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production

更新: 以下示例也可以使用,它使用动态 SQL 与 Savepoints 相结合:

begin 
    rollback; --clear all Transactions
    execute immediate 'begin
                           savepoint SPX;
                       end;';
    rollback to savepoint SPX;
end;

【问题讨论】:

    标签: oracle plsql dynamic-sql


    【解决方案1】:

    问题是在异常传播到外部块之前,会发生隐式 ROLLBACK,这会删除块创建的保存点。

    这是一个重现问题但使用静态 SQL 的示例:

    begin 
        rollback; --clear all Transactions
        savepoint SPX;
        rollback;
        raise no_data_found;
    exception when no_data_found then 
        rollback to savepoint SPX;
    end;
    
    ORA-01086: savepoint 'SPX' never established in this session or is invalid ORA-06512: at line 7
    

    不幸的是,您被这种行为所困扰;动态 SQL 必须在其自己的上下文中运行,如果它引发异常(并且不处理它),则会发出 ROLLBACK。

    您需要在运行动态 SQL 之前创建保存点;或者,您可以抑制 ORA-01086 错误:

    begin 
        rollback; --clear all Transactions
        execute immediate 'begin
                               savepoint SPX;
                               raise no_data_found;  
                           end;';
    exception when no_data_found then 
      begin
        rollback to savepoint SPX;
      exception when others then
        if sqlcode != -1086 /*savepoint never established*/ then
          raise;
        end if;
      end;
    end;
    

    【讨论】:

      【解决方案2】:

      Oracle Doc on the SAVEPOINT statement 中说:

      SQL SAVEPOINT 语句可以作为静态 SQL 嵌入到 PL/SQL 中。

      所以我认为这可以被认为是一种预期的行为。

      【讨论】:

      • 我用一个使用动态 SQL 和保存点的示例更新了我的问题,没有例外。
      • 好主意!似乎在您的第一个示例中,除了引发 EXECUTE 作为一个块失败,破坏了保存点。
      • SAVEPOINT 在 PL/SQL 中有效这一事实与这个问题无关。
      • @JeffreyKemp:这里的关键字是 STATIC。最初的问题是静态 SQL 和动态 SQL 之间是否存在差异。
      猜你喜欢
      • 1970-01-01
      • 2014-02-03
      • 2019-08-13
      • 2016-10-09
      • 2018-02-27
      • 1970-01-01
      • 1970-01-01
      • 2023-04-11
      • 1970-01-01
      相关资源
      最近更新 更多