这感觉就像一个愚蠢的问题,但我在Oracle事务管理概念指南中看到了以下内容:
当任何一个交易结束时,交易结束 发生以下情况:
用户发出COMMIT或ROLLBACK 没有SAVEPOINT子句的语句。
用户运行DDL语句,例如 CREATE,DROP,RENAME或ALTER。如果 当前事务包含任何DML 声明,Oracle首先提交了 事务,然后运行和提交 DDL语句作为新的单一语句 声明交易。
用户与Oracle断开连接。该 当前交易已经提交。
用户进程异常终止。 当前交易已滚动 回来。
我是否要解释最后一点是否意味着如果我发出有错误的查询,该事务将被回滚?
答案 0 :(得分:13)
这是一个有趣的问题!
当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的本机过程语言具有相似的功能。
(**)这仅涉及Oracle中DDL are not transactional以来的DML。还要小心一些更新数据字典的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一样。
答案 1 :(得分:7)
此上下文中的“用户进程”指的是在客户端计算机上运行的进程,该进程创建与Oracle的连接。换句话说,如果您使用应用程序A(SQL*Plus
,TOAD等)连接到Oracle,则用户进程为SQL*Plus
,TOAD等。如果该用户进程在您进入时死亡在事务的中间,该事务将被回滚。一旦PMON发现客户端已经死亡可能需要一些时间,就会发生这种情况 - 对于Oracle来说,区分用户进程的失败与仅发出命令的用户进程并不总是微不足道的那一刻。
答案 2 :(得分:1)
我同意贾斯汀,他的见解是正确的。添加其他信息:作为应用程序开发人员,如果发生错误,应显式调用rollback命令。这意味着,您还应该考虑将语句分组到事务块中。不同技术对事务处理块和回滚的处理方式不同,值得进行一些研究以确保您理解它。