to je zajímavá otázka!
Když Oracle narazí na chybu, vrátí aktuální příkaz , nikoli transakce. Příkaz je jakákoli instrukce nejvyšší úrovně, může to být SQL příkaz (INSERT, UPDATE...) nebo PL/SQL blok.
To znamená, že když příkaz (například procedura pl/sql volaná z java) vrátí chybu, Oracle uvede transakci do stejného logického stavu jako před voláním. To je nesmírně užitečné, nemusíte si dělat starosti s napůl provedenými procedurami (**).
Toto vlákno na AskTom se týká stejného tématu:
[výrok] se buď CELÉ nebo ÚPLNĚ NEDĚJE a funguje to tak, že databáze dělá logický ekvivalent:
begin
savepoint foo;
<<your statement>>
exception
when others then rollback to foo;
RAISE;
end;
Tato funkce je podle mého názoru důvod, proč je mnohem snazší psát kód databáze (*) v pl/sql než v jakémkoli jiném jazyce.
(*) kód, který samozřejmě spolupracuje s Oracle DB, předpokládám, že nativní procedurální jazyky ostatních DBMS mají podobné vlastnosti.
(**) Týká se to pouze DML, protože DDL nejsou v Oracle transakční. Buďte také opatrní u některých balíčků DBMS, které aktualizují datový slovník (například DBMS_STATS
), často provádějí změny podobné DDL a vydávají potvrzení. V případě pochybností nahlédněte do dokumentace.
Aktualizace: toto chování je jedním z nejdůležitějších konceptů v PL/SQL, poskytnu malý příklad, který demonstruje atomicitu příkazů 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 vrátil transakci do bodu těsně před voláním p1. Neexistuje žádná poloviční práce. Je to, jako by procedura p1 nikdy nebyla volána.