Это хорошая записанная транзакция в хранимой процедуре - PullRequest
4 голосов
/ 12 июня 2011

Я впервые использую транзакции, и мне просто интересно, правильно ли я это делаю. Должен ли я что-то изменить? Я вставляю пост (WISP). При вставке сообщения мне нужно сгенерировать идентификатор в таблице commentableEntity и вставить этот идентификатор в таблицу wisp.

ALTER PROCEDURE [dbo].[sp_CreateWisp]
@m_UserId uniqueidentifier,
@m_WispTypeId int,
@m_CreatedOnDate datetime,
@m_PrivacyTypeId int,
@m_WispText nvarchar(200)
AS
BEGIN TRANSACTION

    DECLARE @wispId int

    INSERT INTO dbo.tbl_Wisps
    (UserId,WispTypeId,CreatedOnDate,PrivacyTypeId,WispText)
    VALUES
    (@m_UserId,@m_WispTypeId,@m_CreatedOnDate,@m_PrivacyTypeId,@m_WispText)

    if @@ERROR <> 0
        BEGIN
            ROLLBACK            
            RAISERROR ('Error in adding new wisp.', 16, 1)
            RETURN
        END

    SELECT @wispId = SCOPE_IDENTITY()

    INSERT INTO dbo.tbl_CommentableEntity
    (ItemId)
    VALUES
    (@wispId)

    if @@ERROR <> 0
        BEGIN
            ROLLBACK            
            RAISERROR ('Error in adding commentable entity.', 16, 1)
            RETURN
        END

    DECLARE @ceid int

    select @ceid = SCOPE_IDENTITY()

    UPDATE dbo.tbl_Wisps SET CommentableEntityId = @ceid WHERE WispId = @wispId

    if @@ERROR <> 0
        BEGIN
            ROLLBACK            
            RAISERROR ('Error in adding wisp commentable entity id.', 16, 1)
            RETURN
        END

COMMIT

Использование try / catch на основе ответа @gbn:

ALTER PROCEDURE [dbo].[sp_CreateWisp]
@m_UserId uniqueidentifier,
@m_WispTypeId int,
@m_CreatedOnDate datetime,
@m_PrivacyTypeId int,
@m_WispText nvarchar(200)
AS

SET XACT_ABORT, NOCOUNT ON

DECLARE @starttrancount int

BEGIN TRY
    SELECT @starttrancount = @@TRANCOUNT

    IF @starttrancount = 0
        BEGIN TRANSACTION

        DECLARE @wispId int

        INSERT INTO dbo.tbl_Wisps
        (UserId,WispTypeId,CreatedOnDate,PrivacyTypeId,WispText)
        VALUES
        (@m_UserId,@m_WispTypeId,@m_CreatedOnDate,@m_PrivacyTypeId,@m_WispText)

        SELECT @wispId = SCOPE_IDENTITY()

        INSERT INTO dbo.tbl_CommentableEntity
        (ItemId)
        VALUES
        (@wispId)

        DECLARE @ceid int

        select @ceid = SCOPE_IDENTITY()

        UPDATE dbo.tbl_Wisps SET CommentableEntityId = @ceid WHERE WispId = @wispId

    IF @starttrancount = 0 
        COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION
    RAISERROR ('Error in adding new wisp', 16, 1)
END CATCH
GO

Ответы [ 3 ]

6 голосов
/ 12 июня 2011

Вы бы использовали TRY / CATCH начиная с SQL Server 2005 +

Ваш откат переходит в блок CATCH, но в противном случае ваш код выглядит хорошо (с помощью SCOPE_IDENTITY () и т. Д.). Я бы также использовал SET XACT_ABORT, NOCOUNT ON

Это мой шаблон: Вложенные хранимые процедуры, содержащие шаблон TRY CATCH ROLLBACK?

Edit:

  • Это допускает вложенные транзакции в соответствии с ответом DeveloperX
  • Этот шаблон также допускает транзакции более высокого уровня согласно комментарию Рэнди
1 голос
/ 12 июня 2011

Я никогда не считал хорошей идеей помещать транзакции в хранимую процедуру. Я думаю, что гораздо лучше начать транзакцию на более высоком уровне, чтобы лучше координировать несколько вызовов базы данных (например, хранимых процедур) и обрабатывать их все как одну транзакцию.

1 голос
/ 12 июня 2011

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

, но в этом случае вам следуетиспользуйте блок try catch для обработки исключений и предотвращения открытия транзакции при возникновении исключения

...