това е интересен въпрос!
Когато Oracle срещне грешка, той ще върне текущото изявление , а не сделката. Инструкцията е всяка инструкция от най-високо ниво, може да бъде SQL израз (INSERT, UPDATE...) или PL/SQL блок.
Това означава, че когато оператор (например pl/sql процедура, извикана от java) върне грешка, Oracle ще постави транзакцията в същото логическо състояние, както преди извикването. Това е изключително полезно, не е нужно да се притеснявате за полуизпълнени процедури (**).
Тази тема на AskTom обхваща същата тема:
[изявлението] или се случва ИЗЦЯЛО, или НЕ СЕ случва, и начинът, по който работи, е базата данни логически еквивалент на:
begin
savepoint foo;
<<your statement>>
exception
when others then rollback to foo;
RAISE;
end;
Според мен тази функция е причината да се пише код на база данни (*) много по-лесно в pl/sql, отколкото на всеки друг език.
(*) код, който взаимодейства с Oracle DB, разбира се, предполагам, че родните процедурни езици на другите СУБД имат подобни характеристики.
(**) Това се отнася само за DML, тъй като DDL не са транзакционни в Oracle. Бъдете внимателни и с някои СУБД пакети, които актуализират речника на данните (като 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
Oracle върна транзакцията до точката точно преди да извика p1. Няма свършена половин работа. Сякаш процедурата p1 никога не е била извикана.