oracle - PL/SQL : Contradiction in Oracle document on Implicit Rollbacks

标签 oracle exception plsql rollback

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

"Before running an INSERT, UPDATE, DELETE, or MERGE statement, the database marks an implicit savepoint (unavailable to you). If the statement fails, the database rolls back to the savepoint. Usually, just the failed SQL statement is rolled back, not the whole transaction."

因此,如果我在 PL/SQL 程序中运行 SQL 语句,并且该语句失败,则该语句将自动回滚。没关系。

但同一部分以以下文字结尾:

"If you exit a stored subprogram with an unhandled exception, PL/SQL does not assign values to OUT parameters, and does not do any rollback."

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

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

Stack Overflow 中的相关问题:


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

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

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

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

如果程序是匿名 block (不存在调用者),则相当于从用户语句中调用,失败的用户语句会自动回滚,因此匿名 block 也被回滚。

我认为文档应该更清楚,特别是“并且不做任何回滚”这几个字:

"If you exit a stored subprogram with an unhandled exception, PL/SQL does not assign values to OUT parameters, and does not do any rollback."

最佳答案

这并不矛盾,但必须准确阅读文档,例如

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 不会执行任何回滚,因为第一个插入语句插入的记录仍在表中。然而,如上直接执行DML时,整个第二条插入语句已经回滚到执行第二条语句之前建立的隐式保存点。

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

SELECT col
FROM t
/

no rows selected.

这表明,如果您因未处理的异常退出匿名 block ,Oracle 确实会进行回滚。这将再次指向执行匿名 block 之前建立的隐式保存点。

关于oracle - PL/SQL : Contradiction in Oracle document on Implicit Rollbacks,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25666826/

相关文章:

sql - 在时间范围内对数据进行分组

java - Java 中的 Exception 类在编译时如何链接

database - 如何检查值是否在数据库中而不在 Zend 中抛出异常?

sql - 使用 SQL 逐字反转字符串

xml - 带有子查询的 Oracle 数据透视表

oracle - pl/sql 嵌套循环

java - 如何加快 JPA 中的列表访问速度

Java - 如何为类外变量抛出 IllegalArgumentException

java - 如何读取存储在oracle数据库中的java类中的剪贴板文本?

sql比较带有一些空值的字段