to jest interesujące pytanie!
Gdy Oracle napotka błąd, wycofa bieżące oświadczenie , a nie transakcja. Instrukcja to dowolna instrukcja najwyższego poziomu, może to być instrukcja SQL (INSERT, UPDATE...) lub blok PL/SQL.
Oznacza to, że gdy instrukcja (na przykład procedura pl/sql wywołana z javy) zwróci błąd, Oracle ustawi transakcję w tym samym stanie logicznym, co przed wywołaniem. Jest to niezwykle pomocne, nie musisz się martwić o procedury wykonane w połowie (**).
Ten wątek na AskTom dotyczy tego samego tematu:
[stwierdzenie] albo zdarza się CAŁKOWICIE, albo CAŁKOWICIE NIE DAJ SIĘ, a sposób, w jaki działa baza danych, jest logicznym odpowiednikiem:
begin
savepoint foo;
<<your statement>>
exception
when others then rollback to foo;
RAISE;
end;
Moim zdaniem ta cecha sprawia, że o wiele łatwiej jest napisać kod bazy danych (*) w pl/sql niż w jakimkolwiek innym języku.
(*) kod, który współdziała z bazą danych Oracle, oczywiście, przypuszczam, że natywne języki proceduralne innych DBMS mają podobne cechy.
(**) Dotyczy to tylko DML, ponieważ DDL nie są transakcyjne w Oracle. Uważaj także na niektóre pakiety DBMS, które aktualizują słownik danych (takich jak DBMS_STATS
), często dokonują zmian podobnych do DDL i wydają zatwierdzenia. W razie wątpliwości zapoznaj się z dokumentacją.
Aktualizacja: to zachowanie jest jedną z najważniejszych koncepcji w PL/SQL, przedstawię mały przykład, aby zademonstrować niepodzielność instrukcji 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 cofnął transakcję do punktu tuż przed wywołaniem p1. Nie ma połowy pracy. To tak, jakby procedura p1 nigdy nie została wywołana.