Oracle在出现错误时会回滚事务吗?

9

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

当发生以下任何一种情况时,事务将结束:

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

用户运行DDL语句,例如CREATE、DROP、RENAME或ALTER。如果当前事务包含任何DML语句,则Oracle首先提交该事务,然后作为新的单个语句事务运行并提交DDL语句。

用户断开与Oracle的连接。当前事务将被提交。

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

我是否应该理解最后一点意味着如果我发出一个有错误的查询,事务将被回滚?


@Oliver:我不一定想要或不想要它们。我只是想知道它们是如何工作的。 - Jason Baker
@Oliver,这是 Oracle - 你总是使用事务。 - Jeffrey Kemp
@JeffreyKemp:严格来说,在任何关系型数据库中,您始终在使用事务,只是许多接口会自动提交每个语句。 - beldaz
@beldaz,那正是我的观点 - 没有不使用事务的选项。Oliver似乎误解了你可以选择退出。 - Jeffrey Kemp
http://dba.stackexchange.com/questions/84769/commit-and-rollback-in-oracle-stored-procedure - zloctb
显示剩余2条评论
3个回答

16

这是一个有趣的问题!

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

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

AskTom上的此主题涵盖了相同的主题

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

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

在我看来,这个特性是为什么使用pl/sql编写数据库代码比其他语言更容易的原因。

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

(**)这仅涉及DML,因为DDL在Oracle中不是事务性的。同时,请注意某些更新数据字典的DBMS包(例如DBMS_STATS),它们经常进行类似DDL的更改并发出提交。如果有疑问,请参考文档

更新:这种行为是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一样。


1
你对语句和PL/SQL块的理解是错误的。一个PL/SQL块不是像INSERT、UPDATE或DELETE那样的语句。如果一个PL/SQL块抛出了一个错误,并且没有像你的代码一样的保存点处理,那么你就必须担心半执行的过程。 - Christian13467
2
Christian,那是错误的。如果由客户端调用的顶层PL/SQL块引发异常,则会回滚到调用该块之前的点(假设在介于PL/SQL之间没有提交)。 - Gary Myers
@Christian:我更新了我的答案,希望这能澄清我试图解释的概念。 - Vincent Malgrat
@andrew 我们在谈论 DML,而不是 DDL。我认为从上下文(事务)中很清楚,但我会在我的回答中明确说明。 - Vincent Malgrat

8
在这个上下文中,“用户进程”是指在客户端计算机上运行并创建到Oracle连接的进程。换句话说,如果您使用应用程序A(SQL * Plus、TOAD等)连接到Oracle,则用户进程是SQL * Plus、TOAD等。如果该用户进程在您进行事务操作时意外终止,那么该事务将被回滚。这将在PMON发现客户端已经死亡时发生,这可能需要一些时间 - Oracle不总是轻易区分用户进程失败和用户进程暂停执行命令的情况。

1

我同意Justin的观点,他的洞察力是正确的。补充一些信息:作为应用程序开发人员,如果出现错误,您应该明确调用回滚命令。这意味着,您还应该根据需要将语句分组到事务块中。不同技术处理事务块和回滚的方式不同,值得进行一些研究,以确保您充分理解它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接