首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PL/SQL: Oracle文档中隐式回滚的矛盾

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

Stack Overflow用户
提问于 2014-09-04 13:29:39
回答 1查看 1.1K关注 0票数 2

在文档Oracle数据库PL/SQL语言参考资料11g第2版(11.2)中,“隐式回滚”部分以以下文本开头:

在运行INSERT、UPDATE、DELETE或MERGE语句之前,数据库标记一个隐式保存点(您无法使用)。如果语句失败,数据库将回滚到保存点。通常,只回滚失败的语句,而不是整个事务。

因此,如果我在PL/SQL程序中运行一个SQL语句,而这个句子失败了,那么这个句子就会自动回滚。这没什么。

但同一节以以下案文结尾:

“如果使用未处理的异常退出存储的子程序,则PL/SQL不为OUT参数赋值,而不执行任何回滚。”

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

因此,如果存储的程序包含SQL语句,则该语句将失败,异常不会被捕获,并且我的程序结束,那么SQL语句是否应该回滚?这份文件有矛盾吗?

堆栈溢出中的相关问题:

Update (solved):感谢DrabJay的示例,现在更清楚了:

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

失败的SQL语句的回滚总是完成(独立于程序中)。程序的回滚取决于调用方:

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

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

我认为这份文件应更清楚,特别是在“而不作任何回滚”的字眼上:

“如果使用未处理的异常退出存储的子程序,则PL/SQL不会为OUT参数()分配值,也不会执行任何回滚。”

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-09-04 17:51:58

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

代码语言:javascript
复制
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语句回滚到执行语句之前建立的隐式保存点,因为数据库中不存在任何记录。如果我们继续下去:

代码语言:javascript
复制
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语句的全部回滚到执行第二个语句之前建立的隐式保存点。

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

代码语言:javascript
复制
SELECT col
FROM t
/

no rows selected.

这表明,如果退出带有未处理异常的匿名块,则Oracle会执行回滚操作。这将同样适用于在执行匿名块之前建立的隐式保存点。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25666826

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档