c'est une question intéressante !
Lorsqu'Oracle rencontre une erreur, il annule l'instruction actuelle , pas la transaction. Une instruction est une instruction de niveau supérieur, il peut s'agir d'une instruction SQL (INSERT, UPDATE...) ou d'un bloc PL/SQL.
Cela signifie que lorsqu'une instruction (par exemple une procédure pl/sql appelée depuis java) renvoie une erreur, Oracle mettra la transaction dans le même état logique qu'avant l'appel. C'est extrêmement utile, vous n'avez pas à vous soucier des procédures à moitié exécutées (**).
Ce fil sur AskTom couvre le même sujet :
[l'instruction] se produit ENTIÈREMENT ou NE se produit PAS ENTIÈREMENT et la façon dont cela fonctionne est que la base de données fait l'équivalent logique de :
begin
savepoint foo;
<<your statement>>
exception
when others then rollback to foo;
RAISE;
end;
Cette fonctionnalité, à mon avis, est la raison pour laquelle il est beaucoup plus facile d'écrire du code de base de données (*) en pl/sql que dans n'importe quel autre langage.
(*) code qui interagit avec une base de données Oracle bien sûr, je suppose que les langages procéduraux natifs des autres SGBD ont des fonctionnalités similaires.
(**) Cela ne concerne que les DML puisque les DDL ne sont pas transactionnels dans Oracle. Soyez également prudent avec certains packages SGBD qui mettent à jour le dictionnaire de données (comme DBMS_STATS
), ils effectuent souvent des modifications de type DDL et émettent des commits. Reportez-vous à la documentation en cas de doute.
Mise à jour : ce comportement est l'un des concepts les plus importants en PL/SQL, je vais donner un petit exemple pour démontrer l'atomicité des instructions 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 a annulé la transaction au point juste avant d'appeler p1. Il n'y a pas de travail à moitié fait. C'est comme si la procédure p1 n'avait jamais été appelée.