2013-05-21 9 views
5

Przechodzimy proces przechodzenia z DB2 na SQL Server 2008R2 i jestem trochę obeznany z TSQL. Każda pomoc w lepszym zrozumieniu tego, co się dzieje, byłaby miła. Utworzyliśmy procedurę zwaną RethrowError jak:Zagnieżdżone transakcje SQL Server 2008R2 z RAISERROR

CREATE PROCEDURE RethrowError 
AS 
BEGIN 
    -- Return if there is no error information to retrieve. 
    IF ERROR_NUMBER() IS NULL 
     RETURN; 
PRINT 'yo error'; 

    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(); 
PRINT 'yo doin something'; 

    -- 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. 
     ); 
PRINT 'yo end'; 

    RETURN; 
END 
GO 

Powodem stworzyliśmy procedura jest czysto rozszerzyć na błędy w przyszłości bez konieczności dotknąć wszystkie procedury. Dodałem kilka linii PRINT do celów debugowania.

Moje główne pytanie jest, że mamy procedurę A i na niepowodzenie to wykonuje RethrowError a ja zobaczę wiadomości

yo error 
yo doin something 
yo end 

jak oczekiwano.

CREATE PROCEDURE dbo.A 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE & SET VARIABLES; 
BEGIN TRY 
    BEGIN TRANSACTION MaintainTarget 

    DO SOME STUFF 
END TRY 
BEGIN CATCH 
    EXEC RethrowError; 

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


    IF (XACT_STATE()) = 1 
    BEGIN 

     PRINT 
      N'The transaction is committable. ' + 
      'Rolling back transaction.' 
     ROLLBACK TRANSACTION; 
    END; 

    RETURN -101; 
END CATCH; 
RETURN; 
END 

GO 

jednak stworzyliśmy procedurę, która wykonuje wiele procedur i gdy zagnieżdżona procedura (czyli procedura jest wywoływana przez procedury B) nie powiedzie się tylko wiadomości widzę są

yo error 
yo doin something 

I Nie bardzo rozumiem, dlaczego ostatnia wiadomość już się nie wyświetla.

Procedura B jest podobna do procedury A, ale z niewielką różnicą w połowie.

CREATE PROCEDURE dbo.B 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE & SET VARIABLES; 
BEGIN TRY  
    DO SOME STUFF 
END TRY 
BEGIN CATCH 
COMMIT; 

RETURN -101; 
END CATCH; 
RETURN; 
END 

Każda pomoc dotycząca lepszego zrozumienia tego, co się dzieje, byłaby doceniona.

Odpowiedz

3

Pozwoliłem sobie na edycję twojego kodu, aby naśladować bahaviour, ale utrzymuj to w prostocie (twoja praca, właściwie;).

Twój procA działa poprawnie, ponieważ procedura RethrowError jest wywoływana wewnątrz bloku CATCH procA i wszystko jest wykonywane. Ale w twoim drugim przypadku wszystko nadal dzieje się w bloku TRY procB! Tak więc CATCH część procB uruchamia się natychmiast po wywołaniu RAISERROR w RethrowError.

Ten prosty przykład pokazuje to zachowanie try-catch:

begin try 
    select 1/0 
    print 'doesnt show - div error' 
end try 
begin catch 
    print 'oops' 
    select 1/0 
    print 'this one shows because its in CATCH!' 
end catch 

i tu jest Twój uproszczony kod:

-- "proc B" start 
begin try 
    -- "proc A" start (works fine alone) 
    begin try 
     begin tran 
     select 1/0 --error 
    end try 
    begin catch 
     print 'yo error'; 
     RAISERROR ('RE from RethrowError', 16, 1) --comment this out and see what happens 
     print 'yo end'; 

     IF (XACT_STATE())=-1 or (XACT_STATE())=1 
     BEGIN 
      PRINT N'Rolling back transaction.' 
      ROLLBACK TRANSACTION; 
     end 
    end catch -- "proc A" ends 
end try 
begin catch 
    select error_message(), error_severity(), error_state() -- 
    print 'outer catch'; 
    commit; 
end catch; 

Nadzieja to pomaga.

+1

+1. Aby dodać do tego, [należy zachować ostrożność przy zagnieżdżonych procedurach obsługi błędów w SQL Server 2008] (http://dba.stackexchange.com/q/23805/5203). – GSerg

+0

Dzięki, teraz jest zupełnie jasne. Będę musiał pamiętać, żeby wszystko było prostsze :). – jabrown