Serwisanci dostępni teraz · czynne całą dobę, także w weekendy i świętaWarszawa i okolice · dojazd bezpłatny
Darmowa diagnoza laptopa
Darmowa diagnoza laptopa
Dojazd do klienta bezpłatnie
Dojazd do klienta bezpłatnie
Laptopy zastępcze bezpłatnie
Laptopy zastępcze bezpłatnie
Odbiór i zwrot sprzętu bezpłatnie
Odbiór i zwrot sprzętu bezpłatnie

TRY...CATCH ograniczenia

Termin Definicja
TRY...CATCH ograniczenia

TRY...CATCH nie przechwytuje niektórych błędów krytycznych, np. przerwania połączenia czy zamknięcia sesji.

Zakres działania TRY...CATCH w języku T-SQL

Konstrukcja TRY...CATCH w Microsoft SQL Server służy do obsługi błędów wykonania instrukcji języka Transact-SQL. Instrukcje, które mogą zgłosić błąd, umieszcza się w bloku BEGIN TRY ... END TRY, a reakcję na błąd definiuje w bloku BEGIN CATCH ... END CATCH. Po wystąpieniu błędu sterowanie przechodzi do bloku CATCH, o ile dany błąd może zostać obsłużony przez mechanizm aparatu języka T-SQL i nie przerwie działania sesji.

W bloku CATCH można odczytać informacje diagnostyczne za pomocą funkcji takich jak ERROR_NUMBER(), ERROR_SEVERITY(), ERROR_STATE(), ERROR_PROCEDURE(), ERROR_LINE() oraz ERROR_MESSAGE(). Funkcje te zwracają dane dotyczące błędu obsługiwanego w bieżącym kontekście CATCH. Samo przechwycenie błędu nie oznacza jednak, że operacja została automatycznie cofnięta, transakcja pozostaje poprawna ani że połączenie z SQL Server nadal działa.

TRY...CATCH nie jest uniwersalnym przechwytywaczem wszystkich problemów występujących w środowisku SQL Server. Działa na poziomie wykonywania kodu T-SQL, dlatego nie zastępuje mechanizmów obsługi zerwanych połączeń, limitów czasu po stronie klienta, awarii procesu sqlservr.exe ani diagnostyki infrastruktury. To rozróżnienie ma znaczenie przy projektowaniu procedur składowanych i aplikacji korzystających z bazy.

Błędy, których nie da się obsłużyć w zwykłym bloku CATCH

Jedną z istotnych granic są błędy krytyczne, które kończą wykonywanie zadania, sesji albo procesu. Jeżeli klient wysłał żądanie anulowania, wystąpiło przerwanie typu attention, przekroczono limit czasu po stronie aplikacji albo połączenie zostało zamknięte, SQL Server może nie wykonać dalszej części kodu w oczekiwany sposób. W takiej sytuacji blok CATCH nie powinien być traktowany jako gwarantowany punkt sprzątania zasobów i zapisu komunikatu.

Niektóre błędy o wysokim poziomie ważności mogą zakończyć połączenie z serwerem. W szczególności komunikaty o poziomie ważności od 20 do 25 oznaczają poważne problemy, chociaż dokładne zachowanie zależy od rodzaju błędu i stanu sesji. Jeżeli sesja zostanie zamknięta, kod znajdujący się w CATCH nie ma już działającego kontekstu, w którym mógłby wykonać zapis do tabeli, zwrócić wynik lub zatwierdzić operację. Informację o takim zdarzeniu trzeba często uzyskać z logów SQL Server, sterownika albo aplikacji klienckiej.

Osobną kategorię stanowią błędy kompilacji i błędy rozpoznawania obiektów występujące na tym samym poziomie wykonywania. Przykładowo odwołanie do nieistniejącej tabeli może zostać wykryte podczas kompilowania instrukcji znajdującej się bezpośrednio w bloku TRY. Taki błąd może ominąć lokalny CATCH. Jeżeli podobna instrukcja zostanie uruchomiona na niższym poziomie, na przykład przez sp_executesql albo procedurę składowaną, błąd może już zostać zgłoszony do zewnętrznego bloku CATCH. Nie wolno więc zakładać, że identyczny komunikat zawsze ma identyczną ścieżkę obsługi.

Transakcje, XACT_STATE i konsekwencje błędu

TRY...CATCH nie wykonuje automatycznego ROLLBACK. Jeżeli kod w bloku TRY rozpoczął transakcję i wystąpił błąd, procedura musi sprawdzić stan transakcji oraz zdecydować, czy ją wycofać. Do tego celu służy funkcja XACT_STATE(). Wartość 1 oznacza aktywną i możliwą do zatwierdzenia transakcję, 0 oznacza brak aktywnej transakcji, a wartość -1 wskazuje transakcję niezatwierdzalną, którą można zakończyć wyłącznie przez ROLLBACK TRANSACTION.

Typowy schemat obsługi błędu sprawdza najpierw XACT_STATE(), następnie wycofuje transakcję, gdy jej stan na to wskazuje, i dopiero potem przekazuje błąd dalej. Przykładowo procedura może używać IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;, a następnie wykonać THROW; bez parametrów, aby ponownie zgłosić aktualny błąd. Takie rozwiązanie ogranicza ryzyko pozostawienia blokad lub częściowo wykonanej operacji. Wybór między pełnym wycofaniem a obsługą transakcji zewnętrznej musi wynikać z kontraktu procedury, ponieważ procedura nie zawsze jest właścicielem transakcji.

Istotny jest także poziom izolacji i zakres operacji wykonanych przed błędem. Wycofanie transakcji usuwa jej zmiany, ale nie cofa działań wykonanych poza transakcją, komunikatów zapisanych przez niezależne mechanizmy ani skutków po stronie systemów zewnętrznych. SQL Server może również pozostawić aktywne blokady do czasu zakończenia transakcji. Dlatego poprawna obsługa CATCH obejmuje nie tylko odczyt treści błędu, lecz także uporządkowanie stanu transakcyjnego i świadome przekazanie informacji do warstwy wywołującej.

Diagnoza ograniczeń w procedurze i aplikacji

Przy analizie problemu warto rozdzielić trzy zdarzenia: błąd zgłoszony przez SQL Server, anulowanie żądania przez klienta oraz utratę samego połączenia. Jeżeli aplikacja otrzymuje wyjątek sterownika, ale nie ma wpisu z funkcji ERROR_MESSAGE(), przyczyną może być przerwanie komunikacji przed wejściem do CATCH. Jeżeli kod CATCH zapisuje błąd, lecz użytkownik widzi timeout, trzeba sprawdzić, czy klient nie zakończył oczekiwania wcześniej, mimo że serwer nadal wykonywał operację.

Procedura diagnostyczna powinna rejestrować numer błędu, poziom ważności, stan, nazwę procedury, numer wiersza i treść komunikatu. Warto także zapisywać identyfikator żądania po stronie aplikacji oraz czas rozpoczęcia i zakończenia operacji. Sam zapis w CATCH nie wystarczy dla błędów kończących sesję, dlatego przy zerwanych połączeniach należy porównać log aplikacji z dziennikiem SQL Server i informacjami o połączeniu sieciowym. Nie należy natomiast umieszczać w CATCH kodu, który zakłada, że każda transakcja jest aktywna lub że każda tabela dziennika jest dostępna.

Podczas naprawy problemu należy sprawdzić, czy błąd występuje podczas kompilacji, wykonania instrukcji, zatwierdzania transakcji czy komunikacji z klientem. Pomocne jest uruchomienie minimalnego przypadku reprodukującego problem oraz rozdzielenie kodu statycznego od dynamicznego SQL. W przypadku awarii połączenia konieczna może być obsługa ponowienia operacji po stronie aplikacji, ale retry nie może bezwarunkowo powtarzać instrukcji zmieniających dane. Powtórzenie jest bezpieczne tylko wtedy, gdy operacja ma jasno określoną idempotencję albo korzysta z mechanizmu zabezpieczającego przed podwójnym wykonaniem.

+48 22 100 48 29Zadzwoń teraz · serwisant w 1 godzinę