Udostępnij za pośrednictwem


Za pomocą SPRÓBOWAĆ...POŁOWU w języku Transact-SQL

Błędy w Transact-SQL kodu mogą być przetwarzane przy użyciu TRY…POŁÓW konstruowania podobne do funkcji obsługi wyjątków Microsoft Visual C++ i Microsoft Visual C# języków.TRY…CATCH konstrukcja składa się z dwóch części: Blok TRY i blok CATCH.Gdy wykryto błąd w Transact-SQL instrukcja, która znajduje się wewnątrz blok TRY, sterowanie jest przekazywane do blok CATCH gdzie przetwarzane błąd.

Po blok CATCH obsługuje dany wyjątek, formant jest następnie przenoszony do pierwszego Transact-SQL instrukcja następującą po instrukcja CATCH zakończenia.If the END CATCH statement is the last statement in a stored procedure or trigger, control is returned to the code that invoked the stored procedure or trigger.Transact-SQL statements in the TRY block following the statement that generates an error will not be executed.

Jeśli nie wystąpią błędy wewnątrz blok TRY, kontroli przekazuje oświadczenie niezwłocznie po skojarzona instrukcja CATCH zakończenia.Jeśli instrukcja CATCH końcowy jest ostatniego wyciągu w procedura składowana lub wyzwalacza, sterowanie jest przekazywane do instrukcji, która wywołała procedura składowana lub wyzwalacza.

Blok TRY rozpoczyna się od instrukcja SPRÓBUJ rozpocząć i kończy instrukcją END TRY.Jeden lub więcej Transact-SQL instrukcji można określić między SPRÓBUJ rozpocząć i SPRÓBUJ KOŃCOWEGO sprawozdania.

Blok TRY musi następować niezwłocznie blok CATCH.Blok CATCH rozpoczyna się od instrukcja CATCH rozpocząć i kończy instrukcją END połowu.W Transact-SQL, każdy blok TRY jest skojarzony tylko jeden blok CATCH.

Praca z TRY…CATCH

Podczas korzystania z TRY…CATCH konstrukcji, należy wziąć pod uwagę następujące wytyczne i sugestie:

  • Każdy TRY…CATCH konstrukcja musi znajdować się wewnątrz pojedynczej partia, procedura składowana lub wyzwalacza.Na przykład, nie można umieścić TRY blok w jednej partia i skojarzonym CATCH blok w innej instancji.Poniższy skrypt wygenerowałby błąd:

    BEGIN TRY
        SELECT *
            FROM sys.messages
            WHERE message_id = 21;
    END TRY
    GO
    -- The previous GO breaks the script into two batches,
    -- generating syntax errors. The script runs if this GO
    -- is removed.
    BEGIN CATCH
        SELECT ERROR_NUMBER() AS ErrorNumber;
    END CATCH;
    GO
    
  • Blok TRY musi następować bezpośrednio przez blok CATCH.

  • TRY…CATCH konstrukcje mogą być zagnieżdżane.Oznacza to, że TRY…CATCH konstrukcje mogą być umieszczane wewnątrz innych bloków TRY i połowu.Gdy wystąpi błąd zagnieżdżonego blok TRY, program kontroli jest przenoszona do blok CATCH skojarzony z zagnieżdżonego blok TRY.

  • Aby obsłużyć błąd występujący w danym bloku CATCH, napisz TRY…...Blok określonego bloku CATCH CATCH.

  • Błędy, które mają tego przyczyną ważności 20 lub wyższej Aparat baz danych , aby zamknąć połączenie nie będzie obsługiwany przez TRY…Blok CATCH.Jednak TRY…POŁÓW obsługi błędów z ważności 20 lub wyższym, dopóki połączenie nie zostanie zamknięte.

  • Błędy, które mają ważności 10 lub niższym są uważane za ostrzeżenia lub komunikaty informacyjne i nie są obsługiwane przez TRY…Bloki CATCH.

  • Attentions zostanie zakończona partii, nawet jeśli partia jest w zakres z TRY…CATCH konstrukcji.Obejmuje to uwagi wysłane przez Microsoft transakcja rozproszona Coordinator (MS dtc) po awarii transakcja rozproszona.Usługi MS DTC zarządza transakcjami rozproszonymi.

    Ostrzeżenie

    Jeżeli wykonuje transakcja rozproszona w ramach zakres z TRY bloku wystąpi błąd, wykonywanie jest przenoszone do skojarzonych blok CATCH.transakcja rozproszona przejdzie w stan niemożliwy do zatwierdzenia.Wykonanie blok CATCH może zostać przerwane przez Microsoft Koordynator transakcji rozproszonych, którym zarządza transakcji rozproszonych.Po wystąpieniu błędu usługi MS DTC asynchronicznie powiadamia wszystkie serwery uczestniczących w transakcja rozproszona, a kończy wszystkie zadania uczestniczących w transakcja rozproszona.To powiadomienie jest wysyłane w postaci uwagi, które nie jest obsługiwane przez TRY…Konstrukcja połowu i zakończona partia.Po zakończeniu partia pracy, Aparat baz danych wycofuje wszystkie aktywne niemożliwy do zatwierdzenia transakcji.Jeśli wysłano komunikatu o błędzie, gdy wprowadzona niemożliwy do zatwierdzenia stan transakcji po zakończeniu partia, komunikat o błędzie zostanie wysłana do klient Wykryto i przywracana więcej informacji o transakcjach rozproszonych aplikacji, która wskazuje niemożliwy do zatwierdzenia transakcji, see Transakcji rozproszonych (aparat bazy danych).

Błąd funkcji

TRY…POŁÓW używa następujących funkcji błędu do przechwytywania informacji o błędzie:

  • ERROR_NUMBER() zwraca numer błędu.

  • ERROR_MESSAGE() zwraca pełny tekst komunikatu o błędzie.Tekst zawiera wartości dostarczonych parametrów wymiennych, takich jak długość, nazwy obiektów lub godzin.

  • ERROR_SEVERITY() zwraca wagi błędu.

  • Zwraca ERROR_STATE() numer stanu błędu.

  • ERROR_LINE() zwraca numer wiersza wewnątrz rutynowych, który spowodował błąd.

  • ERROR_PROCEDURE() zwraca nazwę procedura składowana lub wyzwalacz, w którym wystąpił błąd.

Informacje o błędzie są pobierane za pomocą tych funkcji z dowolnego miejsca w zakres blok CATCH TRY…CATCH konstrukcji.Błąd funkcji zwróci wartość NULL, jeśli wywołana poza zakres bloku CATCH.Błąd funkcji można odwoływać się wewnątrz procedura składowana i służy do pobierania informacji o błędzie, gdy procedura składowana jest wykonywane w blok CATCH.Dzięki temu nie trzeba powtórzyć obsługa błędów zablokować kod każdego połowu.W przykładzie kodu postępuj zgodnie z SELECT instrukcja w TRY blok wygeneruje błąd dzielenia przez zero.Błąd będzie obsługiwany przez CATCH blok, która używa procedura składowana, aby przywrócić informacje o błędzie.

USE AdventureWorks2008R2;
GO

-- Verify that the stored procedure does not exist.
IF OBJECT_ID ('usp_GetErrorInfo', 'P') IS NOT NULL
    DROP PROCEDURE usp_GetErrorInfo;
GO

-- Create a procedure to retrieve error information.
CREATE PROCEDURE usp_GetErrorInfo
AS
    SELECT 
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() as ErrorState,
        ERROR_PROCEDURE() as ErrorProcedure,
        ERROR_LINE() as ErrorLine,
        ERROR_MESSAGE() as ErrorMessage;
GO

BEGIN TRY
    -- Generate divide-by-zero error.
    SELECT 1/0;
END TRY
BEGIN CATCH
    -- Execute the error retrieval routine.
    EXECUTE usp_GetErrorInfo;
END CATCH;
GO

Kompilacji i instrukcji -poziom ponownie skompilować błędów

Istnieją dwa typy błędów, które nie są obsługiwane przez TRY…CATCH, jeśli błąd występuje w tym samym wykonanie poziom jako TRY…CATCH konstrukcji:

  • Błędy, takie jak błędy składni, które uniemożliwiają wykonywanie partia kompilacji.

  • Błędy występujące podczas instrukcja -poziom ponowną kompilację, takich jak obiekt nazwa rozdzielczości błędy, powstałe po kompilacji z powodu do rozpoznawania nazw odroczonego.

Podczas partia, procedura składowana lub wyzwolenia, który zawiera TRY…Konstrukcja połowu generuje jeden z tych błędów TRY…Konstrukcja CATCH nie obsługuje tych błędów.Błędy te powróci do aplikacji lub partia odwołujące się do rutynowych generowania błędów.Na przykład, następujący kod ilustruje przykład SELECT instrukcja, która powoduje błąd składni.Jeśli ten kod jest wykonywany w SQL Server Management Studio Edytor kwerend wykonanie nie zostanie uruchomiona, ponieważ partia nie kompilacji.Błąd zostanie zwrócony Edytor kwerend i nie będzie uzyskanie złowionych przez TRY…CATCH.

USE AdventureWorks2008R2;
GO

BEGIN TRY
    -- This PRINT statement will not run because the batch
    -- does not begin execution.
    PRINT N'Starting execution';

    -- This SELECT statement contains a syntax error that
    -- stops the batch from compiling successfully.
    SELECT ** FROM HumanResources.Employee;
END TRY
BEGIN CATCH
    SELECT 
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO

W odróżnieniu od błąd składni w poprzednim przykładzie błąd wystąpi podczas instrukcja -poziom ponowna kompilacja nie przeszkodzi partia kompilowanie, ale zostanie zakończona partia, zaraz po ponownej kompilacji dla instrukcja nie powiedzie się.Na przykład jeśli zadanie partia ma dwie deklaracje i druga instrukcja odwołuje się do tabela, która nie istnieje, rozpoznawanie nazw odroczonego powoduje partia pomyślnie skompilować i uruchomić wykonanie bez powiązanie brakuje tabela planu kwerend, dopóki oświadczenie jest ponownie kompilowana.Partia zatrzymane, kiedy uzyska do instrukcja, która odwołuje się do brakujących tabela i zwraca błąd.Ten typ błędu nie będzie obsługiwany przez TRY…Konstrukcja połowu w tym samym poziom wykonania, w którym wystąpił błąd.Poniższy przykład ilustruje to zachowanie.

USE AdventureWorks2008R2;
GO

BEGIN TRY
    -- This PRINT statement will run because the error
    -- occurs at the SELECT statement.
    PRINT N'Starting execution';

    -- This SELECT statement will generate an object name
    -- resolution error because the table does not exist.
    SELECT * FROM NonExistentTable;
END TRY
BEGIN CATCH
    SELECT 
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO

Można użyć TRY…CATCH do obsługi błędów, które powstaną podczas kompilacji lub instrukcja -poziom ponowną kompilację przez wykonywanie kodu generuje błąd w oddzielnych partia wewnątrz blok TRY.Na przykład można to zrobić przez umieszczenie kodu w procedura składowana lub wykonywanie dynamicznym Transact-SQL za pomocą instrukcja sp_executesql.Dzięki temu TRY…CATCH do połowu błąd przy wyższym poziom wykonania niż wystąpienie błędu.Na przykład poniższy kod przedstawia procedura składowana, która generuje błąd rozpoznawania nazwy obiektu.Partia zawierająca TRY…CATCH konstrukcji jest wykonywany przy wyższym poziom niż procedura składowana; i błąd, który występuje w niższej poziom, połowu.

USE AdventureWorks2008R2;
GO

-- Verify that the stored procedure does not already exist.
IF OBJECT_ID ('usp_MyError', 'P') IS NOT NULL
    DROP PROCEDURE usp_MyError;
GO

CREATE PROCEDURE usp_MyError
AS
    -- This SELECT statement will generate
    -- an object name resolution error.
    SELECT * FROM NonExistentTable;
GO

BEGIN TRY
    -- Run the stored procedure.
    EXECUTE usp_MyError;
END TRY
BEGIN CATCH
    SELECT 
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO

Oto zestaw wyników.

ErrorNumber ErrorMessage
----------- ---------------------------------------
208         Invalid object name 'NonExistentTable'.

Aby uzyskać więcej informacji, zobacz Odroczone rozpoznawanie nazw i kompilacji i "ponownej kompilacji wykonanie planów" sekcja w Wykonanie planu buforowania i ponownego użycia.

Uncommittable transakcji

Wewnątrz TRY…Konstrukcja połowu transakcji można wprowadzić stan, w którym transakcja pozostaje otwarty, ale nie można uwzględnić.Transakcja nie może wykonywać dowolne akcja wygenerowanie zapisu do dziennika transakcji, takie jak modyfikacja danych lub próby przywrócenia punkt zapisu.Jednak w tym stanie blokady nabyte przez transakcję są zachowywane i połączenie również pozostaje otwarty.Skutków transakcji nie są kompensowane aż wydanych instrukcja WYCOFYWANIA lub partia do momentu zakończenia i transakcja jest automatycznie przywracana Aparat baz danych.Jeśli wysłano komunikatu o błędzie, gdy wprowadzona niemożliwy do zatwierdzenia stan transakcji po zakończeniu partia, komunikat o błędzie zostanie wysłana do klient Wykryto i przywracana aplikacji, która wskazuje niemożliwy do zatwierdzenia transakcji.

Transakcja przejdzie w stan niemożliwy do zatwierdzenia wewnątrz TRY blok, gdy wystąpi błąd czy inaczej zakończyły transakcji.Na przykład, większość błędów z języka definicja danych (DDL) instrukcja (takie jak CREATE TABLE), lub większość błędów występujących podczas zestaw XACT_ABORT jest ustawiona na ON, zakończyć transakcję spoza blok TRY, ale przeprowadzenia transakcji niemożliwy do zatwierdzenia wewnątrz blok TRY.

Kod w blok CATCH należy przetestować stan transakcji za pomocą funkcja XACT_STATE.XACT_STATE zwraca -1, jeśli sesja ma niemożliwy do zatwierdzenia transakcji.Blok CATCH nie wolno wykonywać żadnych czynności, które wywoła zapis do dziennika, jeśli XACT_STATE zwraca -1.Poniższy przykład kodu generuje błąd w instrukcja DDL i używa XACT_STATE do testowania stanu transakcji w celu uwzględnienia najbardziej odpowiednich akcja.

USE AdventureWorks2008R2;
GO

-- Verify that the table does not exist.
IF OBJECT_ID (N'my_books', N'U') IS NOT NULL
    DROP TABLE my_books;
GO

-- Create table my_books.
CREATE TABLE my_books
    (
    Isbn        int PRIMARY KEY,
    Title       NVARCHAR(100)
    );
GO

BEGIN TRY
    BEGIN TRANSACTION;
        -- This statement will generate an error because the 
        -- column author does not exist in the table.
        ALTER TABLE my_books
            DROP COLUMN author;
    -- If the DDL statement succeeds, commit the transaction.
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    SELECT
        ERROR_NUMBER() as ErrorNumber,
        ERROR_MESSAGE() as ErrorMessage;

    -- Test XACT_STATE for 1 or -1.
    -- XACT_STATE = 0 means there is no transaction and
    -- a commit or rollback operation would generate an error.

    -- Test whether the transaction is uncommittable.
    IF (XACT_STATE()) = -1
    BEGIN
        PRINT
            N'The transaction is in an uncommittable state. ' +
            'Rolling back transaction.'
        ROLLBACK TRANSACTION;
    END;

    -- Test whether the transaction is active and valid.
    IF (XACT_STATE()) = 1
    BEGIN
        PRINT
            N'The transaction is committable. ' +
            'Committing transaction.'
        COMMIT TRANSACTION;   
    END;
END CATCH;
GO

Obsługa zakleszczenia

TRY…CATCH może służyć do obsługi zakleszczenia.Błąd ofiara zakleszczenie 1205 można złowionych przez blok CATCH i Wstecz, aż zostanie odblokowany wątków można wycofać transakcji.Aby uzyskać więcej informacji o deadlocking, zobacz Deadlocking.

W poniższym przykładzie jak TRY…CATCH może służyć do obsługi zakleszczenia.Ta pierwsza sekcja tworzy tabela, która będzie używana do wykazania stanu zakleszczenie i procedura składowana, która będzie używana do drukowania informacji o błędzie.

USE AdventureWorks2008R2;
GO

-- Verify that the table does not exist.
IF OBJECT_ID (N'my_sales',N'U') IS NOT NULL
    DROP TABLE my_sales;
GO

-- Create and populate the table for deadlock simulation.
CREATE TABLE my_sales 
    (
    Itemid       INT PRIMARY KEY,
    Sales        INT not null
    );
GO

INSERT my_sales (itemid, sales) VALUES (1, 1);
INSERT my_sales (itemid, sales) VALUES (2, 1);
GO
  
-- Verify that the stored procedure for error printing
-- does not exist.
IF OBJECT_ID (N'usp_MyErrorLog',N'P') IS NOT NULL
    DROP PROCEDURE usp_MyErrorLog;
GO

-- Create a stored procedure for printing error information.
CREATE PROCEDURE usp_MyErrorLog
AS
    PRINT 
        'Error ' + CONVERT(VARCHAR(50), ERROR_NUMBER()) +
        ', Severity ' + CONVERT(VARCHAR(5), ERROR_SEVERITY()) +
        ', State ' + CONVERT(VARCHAR(5), ERROR_STATE()) + 
        ', Line ' + CONVERT(VARCHAR(5), ERROR_LINE());
    PRINT 
        ERROR_MESSAGE();
GO

Następujący kod skrypty dla sesja 1 i 2 sesja uruchamiane jednocześnie w dwóch osobnych SQL Server Management Studio połączenia.Zarówno sesje podjęta próba zaktualizowania samych wierszy w tabela.Jedną z sesja powiedzie się podczas pierwszej próby operacji aktualizacji i innych sesja zostanie wybrany jako ofiara zakleszczenie.Błąd ofiara zakleszczenie spowoduje wykonanie przeskoczyć do blok CATCH i transakcja przejdzie Państwo niemożliwy do zatwierdzenia.Wewnątrz blok CATCH ofiara zakleszczenie można wycofać transakcji, a następnie ponów próbę aktualizacji tabela, dopóki aktualizacja powiedzie się lub zostanie osiągnięty limit ponownych prób, pęknięcia.

Sesja 1

Sesja 2

USE AdventureWorks2008R2;
GO
-- Declare and set variable
-- to track number of retries
-- to try before exiting.
DECLARE @retry INT;
SET @retry = 5;
-- Keep trying to update 
-- table if this task is 
-- selected as the deadlock 
-- victim.
WHILE (@retry > 0)
BEGIN
    BEGIN TRY
        BEGIN TRANSACTION;
    
        UPDATE my_sales
        SET sales = sales + 1
        WHERE itemid = 1;
        WAITFOR DELAY '00:00:13';
    
        UPDATE my_sales
        SET sales = sales + 1
        WHERE itemid = 2;
        SET @retry = 0;
        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH 
        -- Check error number.
        -- If deadlock victim error,
        -- then reduce retry count
        -- for next update retry. 
        -- If some other error
        -- occurred, then exit
        -- retry WHILE loop.
        IF (ERROR_NUMBER() = 1205)
            SET @retry = @retry - 1;
        ELSE
            SET @retry = -1;
        -- Print error information.
        EXECUTE usp_MyErrorLog;
  
        IF XACT_STATE() <> 0
            ROLLBACK TRANSACTION;
    END CATCH;
END; -- End WHILE loop.
GO
USE AdventureWorks2008R2;
GO
-- Declare and set variable
-- to track number of retries
-- to try before exiting.
DECLARE @retry INT;
SET @retry = 5;
--Keep trying to update 
-- table if this task is 
-- selected as the deadlock 
-- victim.
WHILE (@retry > 0)
BEGIN
    BEGIN TRY
       BEGIN TRANSACTION;
    
        UPDATE my_sales
        SET sales = sales + 1
        WHERE itemid = 2;
        WAITFOR DELAY '00:00:07';
    
        UPDATE my_sales
        SET sales = sales + 1
        WHERE itemid = 1;
        SET @retry = 0;
        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH 
        -- Check error number.
        -- If deadlock victim error,
        -- then reduce retry count
        -- for next update retry. 
        -- If some other error
        -- occurred, then exit
        -- retry WHILE loop.
        IF (ERROR_NUMBER() = 1205)
            SET @retry = @retry - 1;
        ELSE
            SET @retry = -1;
        -- Print error information.
        EXECUTE usp_MyErrorLog;
  
        IF XACT_STATE() <> 0
            ROLLBACK TRANSACTION;
    END CATCH;
END; -- End WHILE loop.
GO

TRY…CATCH z RAISERROR

RAISERROR mogą być używane w blok TRY lub CATCH TRY…CATCH konstrukcja wpływ na zachowanie obsługi błędów.

RAISERROR, który ma ważności 11-19 wykonywane wewnątrz blok TRY powoduje, że formant transferu skojarzone blok CATCH.RAISERROR, który ma ważności 11-19 wykonywane wewnątrz blok CATCH zwraca błąd do aplikacji wywołującej lub partia.W ten sposób RAISERROR może służyć do zwracania informacji do wywołującego o błędzie, który spowodował blok CATCH do wykonać.Błąd informacji dostarczonych przez TRY…CATCH błąd funkcji można przechwycić w wiadomości RAISERROR, w tym oryginalny numer błędu; Jednakże, numer błędu dla RAISERROR musi być >= 50000.

RAISERROR zawierający ważności 10 lub niższym zwraca komunikat informacyjny do wywoływania partia lub aplikacji bez wywoływania blok CATCH.

RAISERROR zawierający ważności 20 lub wyższej zamyka połączenia bazy danych bez wywoływania blok CATCH.

Następujący kod ilustruje przykład jak RAISERROR może być używany wewnątrz CATCH Blok, aby przywrócić oryginalne informacje o błędzie do wywoływania aplikacji lub partia.procedura składowana usp_GenerateError wykonuje DELETE Instrukcja TRY blok, który generuje naruszenie ograniczenia błąd.Błąd powoduje wykonanie transferu ze skojarzonym CATCH blok wewnątrz usp_GenerateError gdzie procedura składowana usp_RethrowError wykonywane podnieść, używając informacji o naruszenie ograniczenia RAISERROR.Ten błąd, generowany przez RAISERROR jest zwracany do wywoływania partia gdzie usp_GenerateError zostało wykonane i powoduje wykonanie transferu ze skojarzonym CATCH blok w wsadowy wywołujący.

Ostrzeżenie

RAISERROR mogą generować błędy z Państwem od 1 do 127 tylko.Ponieważ Aparat baz danych może podnieść błędy z Państwem 0, zaleca się sprawdzić stan błędu zwracany przez ERROR_STATE przed przekazaniem go jako wartość parametru Państwo RAISERROR.

USE AdventureWorks2008R2;
GO

-- Verify that stored procedure does not exist.
IF OBJECT_ID (N'usp_RethrowError',N'P') IS NOT NULL
    DROP PROCEDURE usp_RethrowError;
GO

-- Create the stored procedure to generate an error using 
-- RAISERROR. The original error information is used to
-- construct the msg_str for RAISERROR.
CREATE PROCEDURE usp_RethrowError AS
    -- Return if there is no error information to retrieve.
    IF ERROR_NUMBER() IS NULL
        RETURN;

    DECLARE 
        @ErrorMessage    NVARCHAR(4000),
        @ErrorNumber     INT,
        @ErrorSeverity   INT,
        @ErrorState      INT,
        @ErrorLine       INT,
        @ErrorProcedure  NVARCHAR(200);

    -- Assign variables to error-handling functions that 
    -- capture information for RAISERROR.
    SELECT 
        @ErrorNumber = ERROR_NUMBER(),
        @ErrorSeverity = ERROR_SEVERITY(),
        @ErrorState = ERROR_STATE(),
        @ErrorLine = ERROR_LINE(),
        @ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');

    -- Build the message string that will contain original
    -- error information.
    SELECT @ErrorMessage = 
        N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 
            'Message: '+ ERROR_MESSAGE();

    -- Raise an error: msg_str parameter of RAISERROR will contain
    -- the original error information.
    RAISERROR 
        (
        @ErrorMessage, 
        @ErrorSeverity, 
        1,               
        @ErrorNumber,    -- parameter: original error number.
        @ErrorSeverity,  -- parameter: original error severity.
        @ErrorState,     -- parameter: original error state.
        @ErrorProcedure, -- parameter: original error procedure name.
        @ErrorLine       -- parameter: original error line number.
        );
GO

-- Verify that stored procedure does not exist.
IF OBJECT_ID (N'usp_GenerateError',N'P') IS NOT NULL
    DROP PROCEDURE usp_GenerateError;
GO

-- Create a stored procedure that generates a constraint violation
-- error. The error is caught by the CATCH block where it is 
-- raised again by executing usp_RethrowError.
CREATE PROCEDURE usp_GenerateError 
AS 
    BEGIN TRY
        -- A FOREIGN KEY constraint exists on the table. This 
        -- statement will generate a constraint violation error.
        DELETE FROM Production.Product
            WHERE ProductID = 980;
    END TRY
    BEGIN CATCH
        -- Call the procedure to raise the original error.
        EXEC usp_RethrowError;
    END CATCH;
GO

-- In the following batch, an error occurs inside 
-- usp_GenerateError that invokes the CATCH block in
-- usp_GenerateError. RAISERROR inside this CATCH block
-- generates an error that invokes the outer CATCH
-- block in the calling batch.
BEGIN TRY  -- outer TRY
    -- Call the procedure to generate an error.
    EXECUTE usp_GenerateError;
END TRY
BEGIN CATCH  -- Outer CATCH
    SELECT
        ERROR_NUMBER() as ErrorNumber,
        ERROR_MESSAGE() as ErrorMessage;
END CATCH;
GO

Zmiana przepływu wykonanie

Aby zmienić kierunek wykonywania, przejdź do mogą być używane w obrębie bloku TRY lub blok CATCH.GOTO mogą również służyć do zakończenia bloku TRY lub blok CATCH; Jednakże GOTO nie można wprowadzić do bloku TRY lub blok CATCH.

Rozwiązanie obsługi błędów w bazie danych AdventureWorks2008R2

AdventureWorks2008R2 Przykładowa baza danych zawiera rozwiązanie obsługi błędów zaprojektowany do rejestrowania informacji o błędach, które zostały złowione przez blok CATCH TRY…Konstrukcja połowów, który można później proszeni lub analizowane.

dbo.Tabela w dzienniku błędów

ErrorLog Tabela rejestruje informacje o numer błędu, wagi błędu, stan błędu, Nazwa procedura składowana lub wyzwalacz, w którym wystąpił błąd, numer wiersza, w którym wystąpił błąd i pełny tekst komunikatu o błędzie.Rejestruje także data i czas, w którym wystąpił błąd i nazwę użytkownika, którego wykonywane rutynowo generuje błąd.Ta tabela jest wypełniana podczas procedura składowana uspLogError jest wykonywana w zakres blok CATCH TRY…Konstrukcja CATCH.

dbo.uspLogError

procedura składowana uspLogError rejestruje informacje o błędach w ErrorLog tabela o błędzie, który spowodował wykonanie transferu do blok CATCH TRY…Konstrukcja CATCH.Dla uspLogError do wstawiania informacji o błędzie do ErrorLog tabela, muszą istnieć następujące warunki:

  • uspLogError wykonywane w zakres bloku CATCH.

  • Jeśli bieżąca transakcja jest w stanie niemożliwy do zatwierdzenia, transakcja jest cofana przed wykonaniem uspLogError.

Parametr wyjściowy @ErrorLogID z uspLogError zwraca ErrorLogID wstawionym za pomocą wiersza uspLogError do ErrorLog tabela.Wartość domyślna, @ErrorLogID 0.W poniższym przykładzie pokazano kod uspLogError.

CREATE PROCEDURE [dbo].[uspLogError] 
    @ErrorLogID [int] = 0 OUTPUT  -- Contains the ErrorLogID of the row inserted
                                  -- by uspLogError in the ErrorLog table.

AS
BEGIN
    SET NOCOUNT ON;

    -- Output parameter value of 0 indicates that error 
    -- information was not logged.
    SET @ErrorLogID = 0;

    BEGIN TRY
        -- Return if there is no error information to log.
        IF ERROR_NUMBER() IS NULL
            RETURN;

        -- Return if inside an uncommittable transaction.
        -- Data insertion/modification is not allowed when 
        -- a transaction is in an uncommittable state.
        IF XACT_STATE() = -1
        BEGIN
            PRINT 'Cannot log error since the current transaction is in an uncommittable state. ' 
                + 'Rollback the transaction before executing uspLogError in order to successfully log error information.';
            RETURN;
        END;

        INSERT [dbo].[ErrorLog] 
            (
            [UserName], 
            [ErrorNumber], 
            [ErrorSeverity], 
            [ErrorState], 
            [ErrorProcedure], 
            [ErrorLine], 
            [ErrorMessage]
            ) 
        VALUES 
            (
            CONVERT(sysname, CURRENT_USER), 
            ERROR_NUMBER(),
            ERROR_SEVERITY(),
            ERROR_STATE(),
            ERROR_PROCEDURE(),
            ERROR_LINE(),
            ERROR_MESSAGE()
            );

        -- Pass back the ErrorLogID of the row inserted
        SELECT @ErrorLogID = @@IDENTITY;
    END TRY
    BEGIN CATCH
        PRINT 'An error occurred in stored procedure uspLogError: ';
        EXECUTE [dbo].[uspPrintError];
        RETURN -1;
    END CATCH
END; 

dbo.uspPrintError

The stored procedure uspPrintError prints information about the error that caused execution to transfer to the CATCH block of a TRY…CATCH construct.uspPrintErrorshould be executed in the scope of a CATCH block; otherwise, the procedure returns without printing any error information.W poniższym przykładzie pokazano kod uspPrintError.

CREATE PROCEDURE [dbo].[uspPrintError] 
AS
BEGIN
    SET NOCOUNT ON;

    -- Print error information. 
    PRINT 'Error ' + CONVERT(varchar(50), ERROR_NUMBER()) +
          ', Severity ' + CONVERT(varchar(5), ERROR_SEVERITY()) +
          ', State ' + CONVERT(varchar(5), ERROR_STATE()) + 
          ', Procedure ' + ISNULL(ERROR_PROCEDURE(), '-') + 
          ', Line ' + CONVERT(varchar(5), ERROR_LINE());
    PRINT ERROR_MESSAGE();
END;

Przykład obsługi błędów

Poniższy przykład ilustruje AdventureWorks2008R2 rozwiązanie obsługi błędów.Kod wewnątrz TRY blok próbuje usunąć rekord z ProductID 980 w Production.Product tabela.Ograniczenia klucza OBCEGO dla tabela zapobiega DELETE instrukcja pomyślną i naruszenie ograniczenia zostanie wygenerowany błąd.Ten błąd powoduje wykonanie transferu do CATCH blok.Wewnątrz CATCH blok, wykonywane są następujące akcje:

  • uspPrintErrorDrukuje informacje o błędzie.

  • Po transakcja jest cofana, uspLogError wprowadza informacje o błędach w ErrorLog tabela i zwraca ErrorLogID wstawionego wiersza w @ErrorLogID OUTPUT parametru.

USE AdventureWorks2008R2;
GO

-- Variable to store ErrorLogID value of the row
-- inserted in the ErrorLog table by uspLogError 
DECLARE @ErrorLogID INT;

BEGIN TRY
    BEGIN TRANSACTION;

    -- A FOREIGN KEY constraint exists on this table. This 
    -- statement will generate a constraint violation error.
    DELETE FROM Production.Product
        WHERE ProductID = 980;

    -- If the delete operation succeeds, commit the transaction.
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    -- Call procedure to print error information.
    EXECUTE dbo.uspPrintError;

    -- Roll back any active or uncommittable transactions before
    -- inserting information in the ErrorLog.
    IF XACT_STATE() <> 0
    BEGIN
        ROLLBACK TRANSACTION;
    END

    EXECUTE dbo.uspLogError @ErrorLogID = @ErrorLogID OUTPUT;
END CATCH; 

-- Retrieve logged error information.
SELECT * FROM dbo.ErrorLog WHERE ErrorLogID = @ErrorLogID;
GO

Zagnieżdżone przykład obsługi błędów

W poniższym przykładzie za pomocą zagnieżdżonego TRY…CATCH konstrukcje.

BEGIN TRY
    BEGIN TRY
        SELECT CAST('invalid_date' AS datetime)
    END TRY
    BEGIN CATCH 
        PRINT 'Inner TRY error number: ' +    
            CONVERT(varchar,ERROR_NUMBER()) + ' on line: ' +
            CONVERT(varchar, ERROR_LINE())
    END CATCH
    SELECT CAST('invalid_int' AS int)
END TRY
BEGIN CATCH
    PRINT 'Outer TRY error mumber: ' + CONVERT(varchar,ERROR_NUMBER())+ 
            ' on line: ' + CONVERT(varchar, ERROR_LINE())
END CATCH

Oto zestaw wyników.

Inner TRY error number: 241 on line: 3

Outer TRY error number: 245 on line: 9