Jakiś czas temu pijąc kawkę w pracy, leniwie przeglądałam kod aplikacji. Nagle - prawie się zachłysnęłam! Kod, który ukazał się moim oczom zaintrygował mnie.
A oto ów kod:
begin
-- some code-- more codebeginCOMMIT;exception when others thenrollback;end;-- log error-- of course, more codeend;
COMMIT w bloku BEGIN/END. Ale czemu? Nigdy nie widziałam takiej konstrukcji. Zapytam.
- A czemu COMMIT w BEGIN/END dałeś?
- A tak, na wszelki wypadek. - słyszę odpowiedź.
Na wszelki wypadek..Hm...
COMMIT zatwierdza zmiany, które zostały w zasadzie już wykonane. Jeśli coś miałoby się nie udać, to raczej wcześniej, w trakcie wykonywania konkretnych operacji takich jak INSERT, UPDATE itp. COMMIT to tylko kropka nad i. (No oczywiście w trakcie COMMITA serwer może stanąć w płomieniach, no ale umówmy się, BEGIN/END tutaj nie pomoże...).
Ale tak wszelki wypadek sprawdzę...
Testy przeprowadziłam na bazie Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production.
-- próba z niepoprawnym insertem
set serveroutput on
begininsert into countries (country_id, country_name, region_id)values ('GEO', 'GEORGIA', 1);begin commit;rollback;dbms_output.put_line('commited');exception when others thenrollback;-- log error dbms_output.put_line('in the commit''s exception');/end; exception when others then -- log errordbms_output.put_line('in the main exception');end;
in the main exception
W przypadku błędnego insertu nawet nie weszliśmy do BEGIN/END; COMMIT'a. Wypadliśmy w głównym EXCEPTION.
-- próba z poprawnym insertem (grupa kontrolna :D)
set serveroutput on
begininsert into countries (country_id, country_name, region_id)values ('GE', 'GEORGIA', 1);begin commit;rollback;dbms_output.put_line('commited');exception when others thenrollback;-- log error dbms_output.put_line('in the commit''s exception');/end; exception when others then -- log errordbms_output.put_line('in the main exception');end;
commited
W przypadku poprawnego insert'a - weszliśmy w BEGIN/END COMMIT'a, transakcja została zatwierdzona. I już.
Nic nieprzewidywalnego.
Ale ale... A co z bazami rozproszonymi? Zobaczmy.
Utworzyłam dwie bazy danych, na jednej mam schemat HR, na drugiej SAL. Szczegółowa struktura nie jest istotna. Na schemacie SAL utworzyłam db link do bazy ze schematem HR.
No to do dzieła!
set serveroutput on
begininsert into countries@hr (country_id, country_name, region_id)values ('GE', 'GEORGIA', 1);commit COMMENT 'ORA-2PC-CRASH-TEST-1';begindbms_output.put_line('commited');exception when others thendbms_output.put_line('in the commit''s exception');-- log errordbms_output.put_line( sqlerrm);end;exception when others thendbms_output.put_line('in the main exception');rollback;-- log errorCOMMITend;/
PL/SQL procedure successfully completed.in the commit's exceptionORA-02050: transaction 3.18.1427577 rolled back, some remote DBs may be in-doubtORA-02059: ORA-2PC-CRASH-TEST-1 in commit comment
Ha! Zepsułam COMMIT! Wspaniale :)
Czyli jednak jest troszeczkę szaleństwa w COMMIT'cie :)
Otaczanie COMMIT'a w BEGIN/END jest zbytnim, niepotrzebnym zabiegiem. Problem może wystąpić jedynie w bazach rozproszonych, a nieco większa uwaga przy projektowaniu może zminimalizować ryzyko. Osobiście nigdy nie byłam świadkiem takiego błędu w praktyce. Nie jest to najwyraźniej częsty błąd.
Także nie bać się, commitować :)
Nieco więcej szczegółów na ten temat wygrzebanych z neta.
Komentarze
Prześlij komentarz