这是存储过程中的良好书面事务

时间:2011-06-12 10:56:54

标签: sql-server tsql stored-procedures transactions scope

这是我第一次使用交易,我只是想知道我做对了。我应该改变什么吗? 我插入帖子(wisp)。插入帖子时我需要在commentableEntity表中生成ID并在wisp表中插入该ID。

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

使用基于@gbn的try / catch回答:

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 个答案:

答案 0 :(得分:6)

自SQL Server 2005 +

以来,您一直使用TRY / CATCH

您的回滚进入CATCH块,但您的代码看起来不错(使用SCOPE_IDENTITY()等)。我还会使用SET XACT_ABORT, NOCOUNT ON

这是我的模板:Nested stored procedures containing TRY CATCH ROLLBACK pattern?

编辑:

  • 根据DeveloperX的回答,这允许嵌套事务
  • 此模板还允许根据Randy的评论
  • 进行更高级别的交易

答案 1 :(得分:1)

我认为它一直不好,但如果你想同时使用多个存储过程,那么不好的原因是每个存储过程独立处理事务

但在这种情况下,您应该使用try catch块进行异常处理,并防止在异常提升时保持事务处理打开

答案 2 :(得分:1)

我从未认为将事务放在存储过程中是个好主意。我认为在更高级别启动事务更好,这样可以更好地协调多个数据库(例如存储过程)调用,并将它们作为单个事务处理。