Транзакция SQL Server с несколькими обновлениями, вставками - PullRequest
2 голосов
/ 21 декабря 2011

Итак, у нас есть несколько хранимых процедур, которые используются во время утреннего SQL-задания, и эти процедуры вызываются последовательно.В случае сбоя одного из запросов внутри процедуры у нас возникает ошибка перехвата / записи в журнал, которую мы делаем для каждого запроса, поэтому мы точно знаем, какая часть не удалась.Но проблема в том, что некоторые из этих процессов очень трудно запустить заново, если что-то не получилось, поэтому я думаю о реализации TRANSACTION в каждом хранимом процессе.

Текущая процедура похожа на эту:

CREATE PROCEDURE [dbo].[spStep01]
( 
    @Return_Message     Varchar(1024)   OUT     -- Error messages returned to the calling program
)
AS
BEGIN

SET NOCOUNT ON;

DECLARE @ErrorCode              int
DECLARE @ApplicationNumber      int             
DECLARE @TaskNumber             int             
DECLARE @TaskCompleted          smallint        
DECLARE @TaskFailed             smallint        
DECLARE @TaskRunning            smallint        
DECLARE @ErrorSeverity          smallint        
DECLARE @ErrorState             smallint        

SELECT @ErrorCode = @@ERROR
SELECT @ApplicationNumber   = 10                
SELECT @TaskNumber          = 1
SELECT @TaskCompleted       = 0
SELECT @TaskFailed          = -1
SELECT @TaskRunning         = 1
SELECT @ErrorSeverity       = 16
SELECT @ErrorState          = 1

/***************************************************************************
*  first insert
***************************************************************************/
    BEGIN TRY   
        INSERT INTO ...
    END TRY
    BEGIN CATCH
        SELECT @Return_Message = 'FAILED - first insert did not populate'
        EXEC dbo.spTrackTask '', @ApplicationNumber, @TaskNumber, @TaskFailed, @Return_Message      
        RAISERROR (@Return_Message, @ErrorSeverity, @ErrorState)
        RETURN 
    END CATCH

/***************************************************************************
*  second insert
***************************************************************************/
    BEGIN TRY   
        INSERT INTO ...
    END TRY
    BEGIN CATCH
        SELECT @Return_Message = 'FAILED -  second insert did not populate'
        EXEC dbo.spTrackTask '', @ApplicationNumber, @TaskNumber, @TaskFailed, @Return_Message      
        RAISERROR (@Return_Message, @ErrorSeverity, @ErrorState)
        RETURN 
    END CATCH


/***************************************************************************
* Procedure has completed successfully
***************************************************************************/
    SELECT @Return_Message = 'SUCCESS - Inserts were complete'
    EXEC dbo.spTrackTask '', @ApplicationNumber, @TaskNumber, @TaskCompleted, @Return_Message   


/*************************************
*  Get the Error Message for @@Error
*************************************/
    IF @ErrorCode <> 0
    BEGIN
        SELECT  @Return_Message = [Description]     -- Return the SQL Server error
          FROM  master.dbo.SYSMESSAGES
         WHERE  error = @ErrorCode
    END

/*************************************
*  Return from the Stored Procedure
*************************************/
    RETURN @ErrorCode                               -- =0 if success,  <>0 if failure

END

Я пытаюсь определить, обернул ли я все блоки TRY/CATCH в TRANSACTION и возникла ошибкаесли откатит все.Я посмотрел вокруг на SO и нашел несколько примеров одного TRY/CATCH блока, но у нас было бы несколько в большинстве сохраненных процедур.У меня нет большого опыта работы с транзакциями, поэтому я не уверен на 100%, как правильно реализовать его в этом случае.

Сработает ли это в TRANSACTION?Или есть лучший способ сделать это?

1 Ответ

8 голосов
/ 21 декабря 2011

Как насчет этого

BEGIN TRANSACTION tx
BEGIN TRY
  @CurrentStep = "First Insert"
  INSERT ...

  @CurrentStep = "Second Insert"
  INSERT ...Second

  IF @@TRANCOUNT > 0
  BEGIN --SUCCESS, nothing failed, now I can commit!!
    SELECT @Return_Message = 'SUCCESS - Inserts were complete'
    EXEC dbo.spTrackTask '', @ApplicationNumber, @TaskNumber, @TaskCompleted, @Return_Message   
    COMMIT TRANSACTION tx;    -- now everything is committed
  END
END TRY

BEGIN CATCH 
  IF @@TRANCOUNT > 0 --something failed
  BEGIN
    IF @CurrentStep = 'First Insert'
      SELECT @Return_Message = 'FAILED - first insert did not populate'
    ELSE IF @CurrentStep = 'Second Insert'
      SELECT @Return_Message = 'FAILED - second insert did not populate'

    EXEC dbo.spTrackTask '', @ApplicationNumber, @TaskNumber, @TaskFailed, @Return_Message      
    RAISERROR (@Return_Message, @ErrorSeverity, @ErrorState)

    ROLLBACK TRAN tx; -- everything is rolled back
  END
END CATCH

Надеюсь, это поможет вам, помните, что все внутри транзакции должно быть зафиксировано или откатано в одном месте, в противном случае вам лучше иметь несколько транзакций.

...