1

我读了这个 Stackoverflow 问题 嵌套存储过程包含 TRY CATCH ROLLBACK 模式?

我需要澄清gbn已回答的事务模板。我不能在那里发表评论和提问。

CREATE PROCEDURE [Name]
AS
SET XACT_ABORT, NOCOUNT ON

DECLARE @starttrancount int

BEGIN TRY
    SELECT @starttrancount = @@TRANCOUNT

    IF @starttrancount = 0
        BEGIN TRANSACTION

       [...Perform work, call nested procedures...]

    IF @starttrancount = 0 
        COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION
    RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
GO

我的问题是!

为什么要使用?

SELECT @starttrancount = @@TRANCOUNT ,而不是直接使用@@TRANCOUNT ??

为什么要检查这个?

IF @starttrancount = 0 开始交易

IF @starttrancount = 0 提交事务

我是 transaction 新手,举例说明会很有帮助。谢谢 :)

4

1 回答 1

0
IF @starttrancount = 0 BEGIN TRANSACTION

IF @starttrancount = 0 COMMIT TRANSACTION

使用这些是因为,@starttrancount 保证只让最外层的存储过程使用事务,因此只存在一个事务。

例子:我们要执行最外层程序,那么事务必须只在最外层程序中使用。

外部存储过程

CREATE PROCEDURE sp_outer
AS
SET XACT_ABORT, NOCOUNT ON

DECLARE @starttrancount int

BEGIN TRY
    SELECT @starttrancount = @@TRANCOUNT -- Initially @@TRANSCOUNT =0

    IF @starttrancount = 0
        BEGIN TRANSACTION     -- @@TRANSCOUNT =1

       EXEC sp_inner  -- Inner Procedure is called with @@TRANSCOUNT =1 
                      -- so that Transaction in inner procedure will not be used. 
                      -- Per Transaction is exists.

    IF @starttrancount = 0 
        COMMIT TRANSACTION    -- @@TRANSCOUNT = 0
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION  -- If Error occurs Rollback takes place.
    RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
GO

2.内部存储过程

CREATE PROCEDURE sp_inner
AS
SET XACT_ABORT, NOCOUNT ON

DECLARE @starttrancount int

BEGIN TRY
    SELECT @starttrancount = @@TRANCOUNT  -- @@TRANCOUNT =1

    IF @starttrancount = 0 
        BEGIN TRANSACTION   -- Skipped

       [...Perform work, call nested procedures...]

    IF @starttrancount = 0 
        COMMIT TRANSACTION  -- Skipped
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION -- if Error Caught Roll back does not happen here
    RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc] -- Error thrown to outer stored procedure.
END CATCH
GO

为什么 SELECT @starttrancount = @@TRANCOUNT ,而不是直接使用 @@TRANCOUNT ?

由于两个存储过程中都存在@@TRANSCOUNT 范围,因此使用@starttrancount 变量来维护过程范围内的值。

于 2013-09-28T08:05:56.537 回答