2013-05-21 19 views
5

Stiamo passando attraverso un processo di passaggio da DB2 a SQL Server 2008R2 e sono un po 'poco familiare con TSQL. Qualsiasi aiuto per capire meglio cosa sta succedendo sarebbe bello. Abbiamo creato una procedura chiamata RethrowError come:Transazioni annidate SQL SERVER 2008R2 con 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 

Il motivo che abbiamo creato la procedura è esclusivamente quello di espandere errori in futuro senza dover toccare tutte le procedure. Ho aggiunto alcune linee di stampa per scopi di debug.

La mia domanda principale è che abbiamo procedura di A e in caso di fallimento esegue RethrowError e vedrò i messaggi

yo error 
yo doin something 
yo end 

come previsto.

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 

Tuttavia, abbiamo creato una procedura che esegue molte procedure e quando una procedura nidificato (procedura vale a dire un essere chiamato mediante procedura B) non gli unici messaggi che vedo sono

yo error 
yo doin something 

I' Non capisco perché l'ultimo messaggio non compare più.

La procedura B è simile alla procedura A ma con una piccola differenza nel pescaggio.

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 

Qualsiasi aiuto su come ottenere una migliore comprensione di ciò che sta accadendo sarebbe apprezzato.

risposta

3

Mi sono permesso di modificare il codice per simulare il bahaviour, ma mantenerlo semplice (il tuo lavoro, in realtà;).

Il tuo procA funziona correttamente, poiché la procedura RethrowError viene chiamata all'interno del blocco CATCH di procA e tutto viene eseguito. Ma nel tuo secondo caso, tutto accade ancora all'interno del blocco TRY di procB! Quindi la parte CATT di procB si attiva immediatamente dopo che RAISERROR in RethrowError viene chiamato.

Questo semplice esempio illustra questo comportamento di 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 

Ed ecco il codice semplificato:

-- "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; 

Spero che questo aiuti.

+1

+1. Per aggiungere a ciò, [attenzione con i gestori di errori annidati in SQL Server 2008] (http://dba.stackexchange.com/q/23805/5203). – GSerg

+0

Grazie, ora è completamente chiaro. Dovrò ricordarmi di rendere le cose più semplici :). – jabrown

Problemi correlati