PL / SQL:关于隐式回滚的Oracle文档中的矛盾

时间:2014-09-04 13:29:39

标签: oracle exception plsql rollback

在文档Oracle Database PL/SQL Language Reference 11g Release 2 (11.2)中,"隐式回滚"部分以本文开头:

  

"在运行INSERT,UPDATE,DELETE或MERGE语句之前,   database标记隐式保存点(对您不可用)。 如果   语句失败,数据库回滚到保存点。通常情况下,   只是失败的SQL语句被回滚,而不是全部   。交易"

因此,如果我将一个SQL语句运行到PL / SQL程序中,并且句子失败,那么该句子将自动回滚。没关系。

但同一部分以本文结尾:

  

"如果退出存储未处理异常的子程序,则PL / SQL   不为OUT参数赋值,不执行任何操作   回滚"

这似乎与第一个文本相反:如果我的程序以未捕获的异常结束,则不执行回滚。但是第一篇文章说如果SQL语句失败,则会自动完成回滚。

因此,如果我的存储程序包含一个SQL语句,句子失败,异常没有被捕获,我的程序结束,那么SQL语句应该回滚吗?该文件是否有矛盾?

Stack Overflow中的相关问题:


更新已解决):感谢DrabJay的示例,现在更清楚了:

  • 一件事就是回滚SQL语句。
  • 另一件事是回滚包含SQL语句的程序。

失败的SQL语句的回滚总是完成(无论是否进入程序)。程序的回滚取决于调用者:

  • 如果回调应用于调用者,则会对程序应用回滚。
  • 如果没有对调用者应用回滚,则不会对程序应用回滚。

如果程序是匿名块(不存在调用者),则相当于从用户语句调用,并且失败的用户语句将自动回滚,因此将回滚匿名块。

我认为该文件应该更加清晰,特别是在单词"并且不做任何回滚":

  

"如果退出存储的子程序,其中包含未处理的异常PL / SQL   不为OUT参数赋值,并且不执行任何操作   回滚"

1 个答案:

答案 0 :(得分:5)

没有矛盾,但必须精确阅读文档e,.g。

CREATE TABLE t
  (col NUMBER(1) NOT NULL)
/

Table created.

CREATE PROCEDURE insert_t1
AS
BEGIN
  INSERT INTO t
    (col)
  SELECT 1 FROM dual
  UNION ALL
  SELECT 2 FROM dual;
  INSERT INTO t
    (col)
  SELECT 9 FROM dual
  UNION ALL
  SELECT 10 FROM dual;
END;
/

Procedure created.

SELECT col
FROM t
/

no rows selected.

INSERT INTO t
SELECT 9 FROM dual
UNION ALL
SELECT 10 FROM dual
/

INSERT INTO t
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column

SELECT col
FROM t
/

no rows selected.

这表明,假设尝试插入两个记录的顺序是指定的,DML语句将回滚到执行语句之前建立的隐式保存点,因为数据库中不存在任何记录。如果我们继续:

SET SERVEROUTPUT ON SIZE 1000000
DECLARE
  CURSOR csr
  IS
    SELECT col
    FROM t
    ORDER BY col;
BEGIN
  BEGIN
    insert_t1;
  EXCEPTION
    WHEN OTHERS THEN
      FOR rec IN csr LOOP
        dbms_output.put_line('COL: ' || rec.col);
      END LOOP;
      RAISE;
  END;
END;
/

COL: 1
COL: 2
DECLARE
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
ORA-06512: at line 15

这表明如果您使用未处理的异常退出存储的子程序,则Oracle不会执行任何回滚,因为第一个insert语句插入的记录仍在表中。但是,如上所述直接执行DML时,整个第二个insert语句已回滚到执行第二个语句之前建立的隐式保存点。

但是,如果我们再尝试查询该表。

SELECT col
FROM t
/

no rows selected.

这表明如果退出带有未处理异常的匿名块,Oracle确实会进行回滚。这将再次发生在执行匿名块之前建立的隐式保存点。