2010-12-10 25 views
6

Ich fand und Artikel in der MSDN-Bibliothek, die erklärt, dass try/catch keine Fehler behandelt, die ausgelöst werden, wenn ein Objekt nicht gefunden werden kann. Also, auch wenn ich eine Transaktion in einem try/catch wickeln, wird die Rollback-Satz nicht ausführen:Transaktionsfehler behandeln, wenn Objekte nicht vorhanden sind

BEGIN TRY 
BEGIN TRANSACTION 

    SELECT 1 FROM dbo.TableDoesNotExists 
    PRINT ' Should not see this' 
    COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 
    ROLLBACK TRANSACTION 
    SELECT 
      ERROR_MESSAGE() 
END CATCH 

--PRINT 'Error Number before go: ' + CAST(@@Error AS VARCHAR) 

go 
PRINT 'Error Count After go: ' + CAST(@@Error AS VARCHAR) 
PRINT 'Transaction Count ' + CAST(@@TRANCOUNT AS VARCHAR) 

Was ist der empfohlene Weg, um Fehler geworfen zu handhaben, wenn ein Objekt nicht nicht vorhanden ist, vor allem, wenn es eine Transaktion beteiligt ist . Sollte ich dieses Bit Code anstelle der letzten zwei print-Anweisungen anheften:

IF @@ERROR <> 0 AND @@TRANCOUNT > 0 
BEGIN 
    PRINT 'Rolling back txn' 
    ROLLBACK TRANSACTION 
END 

go 

PRINT 'Transaction Count again: ' + CAST(@@TRANCOUNT AS VARCHAR) 

Antwort

0

Warum versuchen Sie, Daten aus einer Tabelle abzurufen, die nicht existiert?

Der grundlegende Baustein einer Datenbank ist eine Tabelle. Nicht zu wissen, was in Ihrem Schema ist, versucht im Wesentlichen, SQL als dynamische Sprache zu verwenden, was nicht der Fall ist.

Ich würde Ihr Design überdenken; Ohne mehr über die Tabellen in Ihrer Datenbank und deren beabsichtigten Einsatz zu wissen, ist es schwierig für andere, in dieser Hinsicht zu helfen. Fügen Sie bitte weitere Informationen zu Ihrer Frage hinzu.

EDIT ich gelesen von BOL hatte und die empfohlene Art und Weise Fehler zu behandeln, wenn ein Objekt nicht existiert wie folgt:

können Sie versuchen, verwenden ... CATCH Fehler zu behandeln dass während der Kompilierung auftreten oder Neukompilierung auf Anweisungsebene durch Ausführung des fehlererzeugenden Codes in eine separate Charge innerhalb des TRY-Blocks. Zum Beispiel, indem Sie den Code in einer gespeicherten Prozedur oder durch Ausführen einer dynamischen Transact-SQL-Anweisung mit sp_executesql. Diese ermöglicht TRY ... CATCH, um den Fehler bei eine höhere Ausführungsstufe als die Fehler Auftreten abzufangen.

Getestet habe ich das folgende Vorgehensweise

CREATE PROCEDURE [dbo].[BrokenProcedure] 
AS 
BEGIN 
    SET NOCOUNT ON; 
    SELECT * FROM MissingTable 
END 
GO 

Dann ist es innerhalb eines TRY..CATCH Block namens Verwendung aus:

BEGIN TRY 
    PRINT 'Error Number before: ' + CAST(@@Error AS VARCHAR) 
    EXECUTE [dbo].[BrokenProcedure] 
    PRINT ' Should not see this' 
END TRY 
BEGIN CATCH 
    PRINT 'Error Number in catch: ' + CAST(@@Error AS VARCHAR) 
END CATCH 

in der folgenden Ausgabe Resultierende:

Fehlernummer vorher: 0

Fehlernummer in Fang: 208

Es ist keine perfekte Lösung, wie Sie Prozeduren erstellen müssen (oder dynamischen SQL verwenden) für alle Ihren Tabellenzugriff, aber es ist die Methode, mit MS empfehlen.

+1

Manchmal in dynamischen Umgebungen, Sie wissen nicht, das genaue Schema ; Ein anderer Prozess könnte die Datenbankstruktur ändern. Daher ist es wichtig, dass die normale try/catch-Ausnahmebehandlung wie normal funktioniert. –

+0

Messepunkt. Ja, die Try/Catch-Behandlung sollte korrekt funktionieren, aber ich habe MS nicht verteidigt. Ich stimme dieser Verwendung einer Datenbank einfach nicht zu. – Tony

+0

Tony, dieses Szenario kommt in unserer Test- und Entwicklungsumgebung auf, in der mehrere Entwickler gleichzeitig an Änderungen arbeiten, die sie vornehmen. Dies ist eine Situation, über die ich keine Kontrolle habe, also kann ich sie nicht ändern. Da jedoch Änderungen an Objekten im Test auftreten können, muss ich in der Lage sein, Fehler zu behandeln, die von fehlenden Objekten erzeugt werden, und ich dachte, der try/catch-Mechanismus sollte damit umgehen können. Da es nicht versucht, herauszufinden, die beste Möglichkeit, Transaktionen zu verwenden, damit die Änderungen, für die ich verantwortlich bin, nicht in einem inkonsistenten Zustand enden. – gr928x

0

Jetzt haben Sie ein interessantes Thema (na ja, für mich sowieso). Sie sollten keine Transaktion starten, da der Batch nicht kompiliert wird. Es kann jedoch kompiliert werden, und die erneute Kompilierung der Anweisungsebene schlägt später fehl.

See this question What is wrong with my Try Catch in T-SQL?

jedoch in entweder Fall können Sie SET XACT_ABORT ON verwenden. Dies erhöht die Vorhersagbarkeit, da ein Effekt darin besteht, eine Transaktion automatisch rückgängig zu machen. Es unterdrückt auch 266. Fehler Siehe dieses SO question zu

SET XACT_ABORT ON 
BEGIN TRY 
    BEGIN TRANSACTION 

    SELECT 1 FROM dbo.TableDoesNotExists 
    PRINT ' Should not see this' 
    COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 
    -- not needed, but looks weird without a rollback. 
    -- you could forget SET XACT_ABORT ON 
    -- Use XACT_STATE avoid double rollback errors 
    IF XACT_STATE() <> 0 
     ROLLBACK TRANSACTION 

    SELECT 
      ERROR_MESSAGE() 
END CATCH 

go 
--note, this can't be guaranteed to give anything 
PRINT 'Error Count After go: ' + CAST(@@Error AS VARCHAR) 
PRINT 'Transaction Count ' + CAST(@@TRANCOUNT AS VARCHAR) 
1

Sie können mit OBJECT_ID für die Existenz eines Objekt testen():

IF OBJECT_ID('MyTable') IS NULL RAISERROR('Could not find MyTable.', 18, 0) 
+1

ja, könnte ich aber das ist nicht skalierbar. Stellen Sie sich vor Wenn ich ein Testskript austrage, das 50 Objekte berührt, teste ich jedes einzelne? Es scheint mir, dass try/catch den Fehler zuerst behandeln sollte. – gr928x

Verwandte Themen