这是一个有趣的问题!
当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
4 INSERT INTO t VALUES (2);
5
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一样。