programowanieProgramista baz danych

Jak efektywnie realizować procedury obsługi błędów i debugowania w procedurach przechowywanych SQL? Jakie mechanizmy są przewidziane do łapania i logowania błędów? Czy te podejścia różnią się w różnych systemach baz danych?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

W procedurach przechowywanych można i należy obsługiwać błędy za pomocą specjalnych konstrukcji.

W SQL Server główne mechanizmy to bloki TRY...CATCH, w których wszystkie błędy wewnątrz TRY są łapane, a w CATCH można zarejestrować szczegóły. Dostępne są funkcje takie jak ERROR_NUMBER(), ERROR_MESSAGE() do uzyskania szczegółów.

BEGIN TRY -- Ryzykowna operacja UPDATE Accounts SET balance = balance - 100 WHERE id = 1; END TRY BEGIN CATCH INSERT INTO ErrorLog( ErrorTime, ErrorNumber, ErrorMessage, UserName ) VALUES ( GETDATE(), ERROR_NUMBER(), ERROR_MESSAGE(), SUSER_SNAME() ); -- Dodatkowe przywracanie lub ROLLBACK END CATCH

W Oracle częściej używa się bloków EXCEPTION:

BEGIN UPDATE ...; EXCEPTION WHEN OTHERS THEN INSERT INTO error_log VALUES (..., SQLERRM); END;

Rzeczy, o których warto pamiętać:

  • Nie wszystkie błędy są obsługiwane przez CATCH, na przykład błędy parsowania lub kompilacji spowodują wycofanie transakcji przed wejściem w TRY.
  • Dla logowania informacji ważne jest posiadanie osobnej tabeli dla błędów.
  • Należy logować jak najwięcej: tekst błędu, numer, nazwę użytkownika, parametry operacji.
  • W różnych systemach baz danych składnia i możliwości różnią się.

Pytanie z haczykiem.

Czy wyjątek w bloku CATCH może prowadzić do utraty kontekstu błędu? Jak zrealizować zagnieżdżoną obsługę błędów?

Odpowiedź i przykład: Jeśli w bloku CATCH wystąpi błąd (na przykład z powodu niedostępności tabeli ErrorLog), oryginalny kontekst błędu zostaje utracony, a informacja o przyczynie awarii może być zgubiona.

Aby się zabezpieczyć, encapsulate logowanie w osobnej procedurze z własnym TRY...CATCH, aby zawsze łapać "błąd w obsłudze błędów".

BEGIN TRY -- główny kod END TRY BEGIN CATCH EXEC LogError @Error = ERROR_MESSAGE(); END CATCH -- Procedura LogError sama zawiera swój TRY...CATCH

Historia

Projekt: Raportowanie finansowe. W procedurach przechowywanych dodano bloki TRY...CATCH, ale nie zalogowano parametrów, w których wystąpił błąd. W rezultacie przy łapaniu krytycznych awarii trzeba było ręcznie szukać sytuacji z kopii zapasowej – przyczyna pierwotna była nieoczywista.


Historia

Projekt: Automatyzacja obiegu dokumentów (Oracle). W bloku EXCEPTION zapomniano o zalogowaniu nazwy użytkownika. Po tygodniu dochodzenia odkryliśmy, że ktoś celowo "łamał" dokumenty — ustaliliśmy to tylko na podstawie pośrednich sygnałów w dzienniku audytu.


Historia

Projekt: E-commerce. Procedura przy awarii zapisywała błąd w ErrorLog. Pewnego dnia tabela Log została zablokowana przez rozrastającą się transakcję, a próba logowania doprowadziła do zagnieżdżonego błędu, który nadpisał oryginalną przyczynę i oczyścił stos błędów. Naprawiliśmy to wprowadzając dodatkową tabelę dla krytycznych awarii i wielopoziomowe logowanie.