Ich richte einen Job ein, um eine Liste von Verbindungsservern zu durchlaufen und eine bestimmte Abfrage für jeden einzelnen auszuführen. Ich versuche, die Abfrage in einem TRY-CATCH-Block auszuführen. Wenn also ein Problem mit einem bestimmten Server vorliegt, kann ich es protokollieren und dann mit den anderen Servern fortfahren.
Die Abfrage, die ich in der Schleife ausführe, sieht ungefähr so aus:
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!';
Wenn beim Herstellen der Verbindung zum Server ein Problem auftritt, schlägt der Code sofort fehl und wird nicht in den CATCH
Block übertragen. Wenn der Server eine Verbindung herstellt, die Abfrage jedoch fehlerhaft ist, z. B. durch Null dividieren, wird dies vom CATCH
Block erwartet abgefangen .
Ich habe beispielsweise einen Verbindungsserver mit einem Namen erstellt, von dem ich weiß, dass er nicht existiert. Beim Ausführen des oben genannten bekomme ich nur:
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].
Ich habe BOL weiter gelesen TRY-CATCH
und weiß, dass es keine Fehler ab Stufe 20 abfängt, die die Verbindung unterbrechen, aber dies scheint nicht der Fall zu sein (dies ist nur Stufe 16).
Weiß jemand, warum diese Fehler nicht richtig abgefangen werden?
quelle
PRINT 'Start';
ganz oben im Skript ein einfaches hinzufügen , wird dieses in der Ausgabe gedruckt, obwohl die Verbindung dann fehlschlägt und das Skript mit dem Fehler beendet wird. Das würde also auf einen Laufzeitfehler hinweisen, nicht wahr? Es sei denn, ich verstehe es falsch?PRINT
ich noch densp_testlinkedserver
Anruf im Skript. Tatsächlich wird es nicht mit meinem ursprünglichen (fehlgeschlagenen) Skript gedruckt. Es sieht also so aus, als wäre dies tatsächlich ein Fehler beim Kompilieren , weshalb er nicht abgefangen wird.sp_testlinkedserver
Anruf auskommentiert , aber dasSELECT
als dynamisches SQL gelassen . DasPRINT
tritt nicht auf, wenn Sie den Servernamen direkt referenzieren,BEGIN TRY
da der Fehler zuerst ausgelöst wird.Nach der Untersuchung sieht es so aus, als ob dieser Fehler nicht abgefangen wird, da es sich eher um einen Kompilierungsfehler als um einen Laufzeitfehler handelt. Versuchen Sie Folgendes, um dies zu demonstrieren:
Die anfängliche
PRINT
Anweisung wird weder ausgegeben, noch wird der Fehler "Division durch Null" ausgeführt / abgefangen. Der nicht vorhandene Server führt dazu, dass das Skript sofort fehlschlägt.quelle
Ich hatte kürzlich ein ähnliches Problem, bei dem ich eine entfernte Prozedur aus einem TRY-CATCH heraus aufgerufen habe und die Prozedur fehlgeschlagen ist, weil versucht wurde, einen doppelten Schlüssel einzufügen (Laufzeitfehler der Stufe 16). Der CATCH-Block wurde nicht aufgerufen. Ich habe den Grund in diesem Artikel gefunden: https://technet.microsoft.com/en-us/library/ms191515(v=sql.105).aspx
Die Lösung besteht darin, XACT_ABORT in der aufrufenden Prozedur auf ON zu setzen, bevor die entfernte Prozedur aufgerufen wird. Wenn XACT_ABORT aktiviert ist, wird der CATCH-Block wie erwartet aufgerufen. Sie müssen sich bewusst sein, dass die Einstellung XACT_ABORT an die Remote-Prozedur weitergegeben wird. Dies kann sich auf deren Verhalten auswirken.
quelle
quelle