Konfiguruję zadanie, aby przejrzeć listę połączonych serwerów i wykonać określone zapytanie dla każdego z nich. Próbuję wykonać kwerendę w bloku TRY-CATCH, więc jeśli występuje problem z jednym konkretnym serwerem, mogę go zarejestrować, a następnie kontynuować z innymi serwerami.
Zapytanie, które wykonuję wewnątrz pętli, wygląda mniej więcej tak:
BEGIN TRY
SELECT *
FROM OPENQUERY([server1], 'SELECT 1 AS c;');
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER(), ERROR_MESSAGE();
END CATCH;
PRINT 'We got past the Catch block!';
Jeśli wystąpi problem z połączeniem z serwerem, kod po prostu zawiedzie natychmiast i nie zostanie przesłany do CATCH
bloku. Jeśli serwer łączy się, ale w rzeczywistym zapytaniu wystąpił błąd, np. Podziel przez zero, jest to wychwytywane zgodnie z oczekiwaniami CATCH
bloku.
Na przykład utworzyłem serwer połączony z nazwą, o której wiem, że nie istnieje. Wykonując powyższe otrzymuję:
OLE DB provider "SQLNCLI" for linked server "nonserver" returned message
"Login timeout expired".
OLE DB provider "SQLNCLI" for linked server "nonserver" returned message
"An error has occurred while establishing a connection to the server.
When connecting to SQL Server 2005, this failure may be caused by the
fact that under the default settings SQL Server does not allow remote
connections.".
Msg 53, Level 16, State 1, Line 0
Named Pipes Provider: Could not open a connection to SQL Server [53].
Przeczytałem BOL TRY-CATCH
i wiem, że nie będzie on wychwytywał błędów poziomu 20+, które przerywają połączenie, ale wydaje się, że tak nie jest (tylko poziom 16).
Czy ktoś wie, dlaczego te błędy nie są wychwytywane poprawnie?
źródło
PRINT 'Start';
na samym początku skryptu, zostanie on wydrukowany w danych wyjściowych, nawet jeśli połączenie nie powiedzie się i skrypt zakończy działanie z błędem. Oznaczałoby to błąd w czasie wykonywania , prawda? Chyba że źle to zrozumiem?PRINT
, wciąż miałemsp_testlinkedserver
wezwanie w skrypcie. W rzeczywistości nie jest drukowany przy użyciu mojego oryginalnego (nieudanego) skryptu. Wygląda więc na to, że jest to błąd czasu kompilacji i dlatego nie zostaje złapany.sp_testlinkedserver
połączenie, ale zostawiłemSELECT
jako dynamiczny SQL.PRINT
Nie wystąpić, jeśli odwołać się do nazwy serwera bezpośrednio, tak jak sugerował wcześniej,BEGIN TRY
nigdy nie zostanie wprowadzony, ponieważ błąd jest podniesiona w pierwszej kolejności.Po zbadaniu wygląda na to, że ten błąd nie został wyłapany, ponieważ jest to błąd czasu kompilacji, a nie błąd czasu wykonywania. Aby to zademonstrować, spróbuj wykonać następujące czynności:
Instrukcja początkowa
PRINT
nie otrzymuje danych wyjściowych, ani błąd dzielenia przez zero nie jest wykonywany / wychwytywany. Nieistniejący serwer powoduje natychmiastową awarię skryptu.źródło
Ostatnio miałem podobny problem, w którym wywołałem zdalną procedurę z poziomu TRY-CATCH, a procedura nie powiodła się z powodu próby wstawienia duplikatu klucza (błąd czasu wykonania poziomu 16). Blok CATCH nie został wywołany. Znalazłem przyczynę w tym artykule: https://technet.microsoft.com/en-us/library/ms191515(v=sql.105).aspx
Rozwiązaniem jest ustawienie XACT_ABORT ON w procedurze wywoływania przed wywołaniem procedury zdalnej. Gdy XACT_ABORT jest włączony, CATCH jest wywoływany zgodnie z oczekiwaniami. Musisz pamiętać, że ustawienie XACT_ABORT jest propagowane do procedury zdalnej, co może wpłynąć na jego zachowanie.
źródło
źródło