2013-05-21 6 views
5

Мы проходим процесс перехода с DB2 на SQL Server 2008R2, и я немного незнакомый с TSQL. Любая помощь, позволяющая лучше понять, что происходит, будет приятной. Мы создали процедуру под названием RethrowError как:SQL SERVER 2008R2 Вложенные транзакции с 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 

Причина мы создали процедуру чисто для расширения на ошибки в будущем без необходимости прикасаться все процедуры. Я добавил несколько строк PRINT для целей отладки.

Мой главный вопрос заключается в том, что у нас есть метод А и при неудачном выполняет RethrowError и я буду видеть сообщения

yo error 
yo doin something 
yo end 

, как и ожидалось.

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 

Однако мы создали процедуру, которая выполняет множество процедур и когда вложенная процедура (т.е. процедура А вызывается с помощью процедуры B) не единственные сообщения, которые я вижу в

yo error 
yo doin something 

Я m не совсем понимают, почему последнее сообщение больше не появляется.

Процедура B аналогична процедуре A, но с небольшой разницей в вылове.

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 

Любая помощь в получении лучшего понимания того, что происходит, будет оценена по достоинству.

ответ

3

Я разрешил себе редактировать свой код, чтобы имитировать bahaviour, но держите его простым (ваша работа, фактически;).

Ваш procA отлично работает, потому что процедура RethrowError вызывается внутри блока CATCH procA, и все выполняется. Но во втором случае все это происходит внутри блока TRY procB! Поэтому CATCH-часть procB срабатывает сразу же после вызова RAISERROR в RetrowError.

Этого простой пример демонстрирует это поведение 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 

А вот ваш упрощенный код:

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

Надеется, что это помогает.

+1

+1. Чтобы добавить к этому, будьте осторожны с вложенными обработчиками ошибок в SQL Server 2008 (http://dba.stackexchange.com/q/23805/5203). – GSerg

+0

Спасибо, теперь совершенно ясно. Я буду иметь в виду, чтобы сделать вещи более простыми :). – jabrown

Смежные вопросы