Oracle是否因错误而回滚事务?

Jas*_*ker 8 sql oracle plsql transactions oracle10g

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

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

用户发出不带SAVEPOINT子句的COMMIT或ROLLBACK语句.

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

用户断开与Oracle的连接.当前事务已提交.

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

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

Vin*_*rat 13

这是个有趣的问题 !

当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;
Run Code Online (Sandbox Code Playgroud)

在我看来,这个特性是为什么在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
Run Code Online (Sandbox Code Playgroud)

Oracle在调用p1之前将事务回滚到了这一点.没有完成一半的工作.好像从未调用过程p1.

  • 克里斯蒂安,这是错的.如果由客户端调用的顶级PL/SQL块引发异常,那么在调用该块之前会回滚到该点(假设在介入的PL/SQL中没有提交). (2认同)

Jus*_*ave 8

此上下文中的"用户进程"指的是在客户端计算机上运行的进程,该进程创建与Oracle的连接.换句话说,如果您使用应用程序A(SQL*Plus,TOAD等)连接到Oracle,则用户进程是SQL*Plus,TOAD等.如果该用户进程在您处于事务中间时死亡,则该事务将是回滚.一旦PMON发现客户端已经死亡可能需要一些时间,就会发生这种情况 - 对于Oracle来说,区分用户进程的失败与仅发出命令的用户进程并不总是微不足道的此时此刻.