Хранимая процедура транзакции - PullRequest
17 голосов
/ 06 июня 2011

Раньше я никогда не использовал транзакцию, фиксацию и откат, и теперь мне нужно использовать одну. Я проверил в Интернете и т. Д. Примеры, чтобы убедиться, что я действительно использую это правильно, но я все еще не уверен, правильно ли я закодировал это. Я надеюсь, что кто-то может рассмотреть и посоветовать мне, если это кажется правильным.

В основном у меня есть 2 базы данных для приложения. Одним из них является архив - это означает, что данные, которыми пользователи больше не будут манипулировать, будут перемещены в эту БД. Но если им это когда-нибудь понадобится, я перенесу необходимые данные обратно в основную базу данных для использования. Мой сохраненный процесс ниже:

CREATE PROCEDURE [dbo].[spReopenClosed] 
(
    @Return_Message VARCHAR(1024) = ''  OUT,        
    @IID        uniqueidentifier,
    @OpenDate   smalldatetime,
    @ReopenedBy uniqueidentifier
)
AS
BEGIN
    SET NOCOUNT ON;

/******************************
*  Variable Declarations
*******************************/
    DECLARE     @ErrorCode  int  



/******************************
*  Initialize Variables
*******************************/

    SELECT @ErrorCode = @@ERROR

    IF @ErrorCode = 0

    BEGIN TRANSACTION
        /****************************************************************************
        * Step 1
        * Copy the Closed from the Archive
        ****************************************************************************/
        INSERT INTO OPS.dbo.SM_T_In
        SELECT          
        FROM OPS_ARCHIVE.Archive.SM_T_In    W
        WHERE W.GUID = @IID
            AND W.OpenDate = @OpenDate


        IF @ErrorCode <> 0
            BEGIN
                -- Rollback the Transaction
                ROLLBACK

                RAISERROR ('Error in Copying from the archive', 16, 1)
                RETURN
            END


        /****************************************************************************
        * Step 2
        * copy the notes
        ****************************************************************************/
        INSERT INTO OPS.dbo.SM_T_Notes
        SELECT 
        FROM OPS_ARCHIVE.Archive.SM_T_Notes W
        WHERE W.GUID = @IID

        IF @ErrorCode <> 0
            BEGIN
                -- Rollback the Transaction
                ROLLBACK

                RAISERROR ('Error in copying the notes', 16, 1)
                RETURN
            END

        /****************************************************************************
        * Step 3
        * Delete the from the Archive - this will also delete the notes
        ****************************************************************************/
        DELETE
        FROM OPS_ARCHIVE.Archive.SM_T_In
        WHERE OPS_ARCHIVE.Archive.SM_T_In.GUID = @IID

        IF @ErrorCode <> 0
            BEGIN
                -- Rollback the Transaction
                ROLLBACK

                RAISERROR ('Error in deleting the items from the Archive', 16, 1)
                RETURN
            END

        COMMIT

        BEGIN
            SELECT  @ErrorCode  = @@ERROR

            IF @ErrorCode = 0
                    SELECT  @Return_Message = 'All data was moved over'
        END



/*************************************
*  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

У меня есть две вставки, которые перемещают данные из 2 таблиц из базы данных архива. Если эти вставки пройдут успешно, я удалю данные из архивной базы данных. Буду признателен за любые отзывы по этому поводу, мне нужно убедиться, что я делаю это правильно.

Спасибо

Ответы [ 2 ]

32 голосов
/ 06 июня 2011

О, хорошо, я быстро переписал ваш SP, используя концепцию TRY CATCH и СДЕЛКУ , как вы просили, но я не проверял.

Этот код будет работать в SQL 2005/2008

Дайте мне знать, может ли этот отзыв быть полезным для вас

CREATE PROCEDURE [dbo].[spReopenClosed] 
(
    @Return_Message VARCHAR(1024) = ''  OUT,        
    @IID        uniqueidentifier,
    @OpenDate   smalldatetime,
    @ReopenedBy uniqueidentifier
)
AS

    SET NOCOUNT ON;

/******************************
*  Variable Declarations
*******************************/
    DECLARE     @ErrorCode  int  
    DECLARE     @ErrorStep  varchar(200)

/******************************
*  Initialize Variables
*******************************/

    SELECT @ErrorCode = @@ERROR

BEGIN TRY

    BEGIN TRAN
        /****************************************************************************
        * Step 1
        * Copy the Closed from the Archive
        ****************************************************************************/

        SELECT @ErrorStep = 'Error in Copying from the archive';

        INSERT INTO OPS.dbo.SM_T_In
        SELECT *         
        FROM OPS_ARCHIVE.Archive.SM_T_In
        WHERE GUID = @IID
            AND W.OpenDate = @OpenDate


        /****************************************************************************
        * Step 2
        * copy the notes
        ****************************************************************************/

        SELECT @ErrorStep = 'Error in copying the notes'

        INSERT INTO OPS.dbo.SM_T_Notes
        SELECT *
        FROM OPS_ARCHIVE.Archive.SM_T_Notes
        WHERE GUID = @IID

        /****************************************************************************
        * Step 3
        * Delete the from the Archive - this will also delete the notes
        ****************************************************************************/

        SELECT @ErrorStep = 'Error in deleting the items from the Archive'

        DELETE
        FROM OPS_ARCHIVE.Archive.SM_T_In
        WHERE OPS_ARCHIVE.Archive.SM_T_In.GUID = @IID

    COMMIT TRAN

    SELECT  @ErrorCode  = 0, @Return_Message = 'All data was moved over'

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

END TRY

BEGIN CATCH
    /*************************************
    *  Get the Error Message for @@Error
    *************************************/
    IF @@TRANCOUNT > 0 ROLLBACK

    SELECT @ErrorCode = ERROR_NUMBER()
        , @Return_Message = @ErrorStep + ' '
        + cast(ERROR_NUMBER() as varchar(20)) + ' line: '
        + cast(ERROR_LINE() as varchar(20)) + ' ' 
        + ERROR_MESSAGE() + ' > ' 
        + ERROR_PROCEDURE()

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

END CATCH
3 голосов
/ 06 июня 2011

Во-первых, базы данных достаточно надежны. И если они терпят неудачу, у вас есть большая проблема, чем обработка отдельных транзакций. Так что мой отзыв будет таким: у вас слишком много ошибок для простой транзакции. Ошибка вставки - это настолько необычное событие, что обычно вы не пишете код для его обработки.

Во-вторых, этот код не будет "ловить" ошибки:

IF @ErrorCode <> 0

Ошибка в выражении SQL приведет к прерыванию хранимой процедуры и ее возврату клиенту. Чтобы обработать ошибку в хранимой процедуре, вам нужно попробовать ... поймать .

В-третьих, я стараюсь избегать raiserr. Он может делать неожиданные вещи как на стороне сервера, так и на стороне клиента. Вместо этого рассмотрите возможность использования параметра output для возврата информации об ошибке в клиентскую программу.

...