【问题标题】:Does Oracle roll back the transaction on an error?Oracle 是否会在出现错误时回滚事务?
【发布时间】:2010-11-30 21:16:39
【问题描述】:

这感觉像是一个愚蠢的问题,但我在 Oracle 事务管理概念指南中看到以下内容:

当任何一个交易结束时 发生以下情况:

用户发出 COMMIT 或 ROLLBACK 没有 SAVEPOINT 子句的语句。

用户运行 DDL 语句,例如 创建、删除、重命名或更改。如果 当前事务包含任何 DML 语句,Oracle 首先提交 事务,然后运行并提交 DDL 语句作为一个新的、单一的 对帐单交易。

用户与 Oracle 断开连接。这 当前事务已提交。

用户进程异常终止。 当前事务被滚动 返回。

我是否将最后一点解释为如果我发出一个有错误的查询,事务将被回滚?

【问题讨论】:

  • 实际上,这对我来说是一个非常有趣的问题。 Postgres 出错时回滚,我经常觉得它很烦人(想知道 Oracle 是否做了类似的事情)。
  • 告诉我,如果您不想回滚错误,为什么还要使用事务?这是交易的主要目的之一。
  • @Oliver:我不一定想要或不想要它们。我只是想知道它们是如何工作的。
  • @Oliver,这是 Oracle - 你总是使用事务。
  • @JeffreyKemp:严格来说,您总是在任何关系数据库中使用事务,只是有很多接口自动提交每个语句。

标签: sql oracle transactions plsql oracle10g


【解决方案1】:

这是一个有趣的问题!

当Oracle遇到错误时,它会回滚当前的语句,而不是事务。语句是任何顶级指令,它可以是 SQL 语句(INSERT、UPDATE...)或 PL/SQL 块。

这意味着当一条语句(例如从 java 调用的 pl/sql 过程)返回错误时,Oracle 会将事务置于与调用之前相同的逻辑状态。这非常有帮助,您不必担心程序执行一半(**)。

This thread on AskTom covers the same topic:

[声明]要么完全发生,要么完全不发生,并且 工作方式是数据库执行以下逻辑等效项:

begin
   savepoint foo;
   <<your statement>>
exception
   when others then rollback to foo; 
                    RAISE;
end;

在我看来,这个特性就是为什么用 pl/sql 编写数据库代码 (*) 比使用任何其他语言都容易得多的原因。

(*) 与 Oracle DB 交互的代码当然,我想其他 DBMS 的本机过程语言也有类似的功能。

(**) 这仅涉及 DML,因为 Oracle 中的 DDL are not transactional。还要小心一些更新数据字典的 DBMS 包(例如DBMS_STATS),它们经常进行类似 DDL 的更改并发出提交。如有疑问请参考documentation

更新:此行为是 PL/SQL 中最重要的概念之一,我将提供一个小示例来演示 pl/sql 语句的原子性

SQL> CREATE TABLE T (a NUMBER);

Table created

SQL> CREATE OR REPLACE PROCEDURE p1 AS
  2  BEGIN
  3     -- this statement is successful
  4     INSERT INTO t VALUES (2);
  5     -- this statement will raise an error
  6     raise_application_error(-20001, 'foo');
  7  END p1;
  8  /

Procedure created

SQL> INSERT INTO t VALUES (1);

1 row inserted

SQL> EXEC p1;

begin p1; end;

ORA-20001: foo
ORA-06512: at "VNZ.P1", line 5
ORA-06512: at line 2

SQL> SELECT * FROM t;

         A
----------
         1

Oracle 已将事务回滚到调用 p1 之前的位置。没有完成一半的工作。就好像过程 p1 从未被调用过一样。

【讨论】:

  • 您对语句和 PL/SQL 块的看法是错误的。 PL/SQL 块不是语句,而不是 INSERT、UPDATE 或 DELETE。如果 PL/SQL 块抛出错误并且没有像您的代码那样的保存点处理,那么您必须担心半执行过程。
  • 克里斯蒂安,那是错误的。如果由客户端调用的顶级 PL/SQL 块引发异常,则将回滚到调用该块之前的点(假设在介入的 PL/SQL 中没有提交)。
  • @Christian:我更新了我的答案,希望这能澄清我试图解释的概念。
  • @andrew 我们在这里讨论的是 DML,而不是 DDL。我认为从上下文(交易)中可以清楚地看出,但我会在回答中准确说明。
【解决方案2】:

在此上下文中的“用户进程”是指在客户端计算机上运行的创建与 Oracle 的连接的进程。换句话说,如果您使用应用程序 A(SQL*Plus、TOAD 等)连接到 Oracle,则用户进程是 SQL*Plus、TOAD 等。如果该用户进程在您处于事务,该事务将被回滚。这将在 PMON 发现客户端已经死机时立即发生,这可能需要一些时间——对于 Oracle 来说,区分用户进程的失败和只是没有发出命令的用户进程并不总是微不足道的。瞬间。

【讨论】:

    【解决方案3】:

    我同意贾斯汀的观点,他的见解是正确的。添加附加信息:作为应用程序开发人员,如果发生错误,您应该显式调用回滚命令。这意味着,您还应该考虑将语句分组到适当的事务块中。不同的技术对事务块和回滚的处理方式不同,值得进行一些研究以确保您能很好地理解它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-21
      • 1970-01-01
      • 2013-12-31
      • 2019-07-25
      • 1970-01-01
      • 2013-05-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多