【问题标题】:SAVE TRANSACTION vs BEGIN TRANSACTION (SQL Server) how to nest transactions nicelySAVE TRANSACTION vs BEGIN TRANSACTION(SQL Server)如何很好地嵌套事务
【发布时间】:2012-03-15 02:51:55
【问题描述】:

我有一个需要设置保存点的存储过程,以便它可以在某些情况下撤消它所做的一切并将错误代码返回给调用者,或者接受/提交它并将成功返回给调用者。但是无论调用者是否已经开始交易,我都需要它来工作。该文档在这个主题上非常混乱。这是我认为可行的方法,但我不确定所有的后果。

问题是 - 这个Stored Procedure (SP) 被其他人调用。所以我不知道他们是否已经开始交易了......即使我要求用户开始交易才能使用我的SP,我仍然对Save Points的正确使用有疑问......

我的 SP 将测试交易是否正在进行,如果没有,则以BEGIN TRANSACTION 开头。如果事务已经在进行中,它将改为使用SAVE TRANSACTION MySavePointName 创建一个保存点,并保存我所做的事实。

然后如果我必须回滚我的更改,如果我之前做了一个BEGIN TRANSACTION,那么我会ROLLBACK TRANSACTION。如果我做了保存点,那么我会ROLLBACK TRANSACTION MySavePointName。这种情况似乎效果很好。

这是我有点困惑的地方——如果我想保留我已经完成的工作,如果我开始交易,我将执行COMMIT TRANSACTION。但是如果我创建了一个保存点呢?我尝试了COMMIT TRANSACTION MySavePointName,但随后调用者尝试提交其事务并收到错误:

COMMIT TRANSACTION 请求没有对应的 BEGIN TRANSACTION。

所以我想知道 - 可以回滚保存点(有效:ROLLBACK TRANSACTION MySavePointName 不会回滚调用者的事务)。但也许永远不需要“提交”它?它只是停留在那里,以防您需要回滚到它,但是一旦原始事务被提交(或回滚)就消失了?

如果有“更好”的方式来“嵌套”交易,也请说明一下。我还没有想出如何与BEGIN TRANSACTION 嵌套,但只能回滚或提交我的内部事务。似乎ROLLBACK 将始终回滚到顶部事务,而COMMIT 只是减少@@trancount

【问题讨论】:

  • 您的发现可能值得作为答案发布。
  • @Andriy 好的,这就是我所做的 - 删除了我的编辑并将其用作答案。谢谢。

标签: sql-server transactions nested-transactions


【解决方案1】:

我相信我现在已经想通了,所以我会回答我自己的问题......

如果您想了解更多详细信息,我什至将我的发现写在博客上,http://geekswithblogs.net/bbiales/archive/2012/03/15/how-to-nest-transactions-nicely---quotbegin-transactionquot-vs-quotsave.aspx

所以我的 SP 以这样的方式开始,如果没有,则开始新事务,但如果已经在进行中,则使用保存点:

DECLARE @startingTranCount int
SET @startingTranCount = @@TRANCOUNT

IF @startingTranCount > 0
    SAVE TRANSACTION mySavePointName
ELSE
    BEGIN TRANSACTION
-- …

然后,当准备好提交更改时,您只需要在我们自己启动事务的情况下提交:

IF @startingTranCount = 0
    COMMIT TRANSACTION

最后,只回滚到目前为止所做的更改:

-- Roll back changes...
IF @startingTranCount > 0
    ROLLBACK TRANSACTION MySavePointName
ELSE
    ROLLBACK TRANSACTION

【讨论】:

  • 有什么理由在save transaction之后不开始新的嵌套事务?
  • 下面是关于嵌套事务的文章的链接。如果提交了嵌套事务,它会降低嵌套事务计数,但不会提交任何内容。因此,如果外部事务已提交,则一切都已回滚,如果已回滚,则一切都将回滚,包括您的“已提交”事务。如果嵌套事务执行回滚,它会回滚自身和外部事务。如果您只想回滚自己的事务而不影响您已经在其中的任何事务,请使用此处描述的技术。
  • 这是关于嵌套事务的文章:technet.microsoft.com/en-us/library/…
  • 如何进行部分提交?在过程中提交很少的操作(例如导入原始数据),并且在处理这些数据时也会向实体框架提出错误。但是我有实体框架总是回滚所有内容(包括导入的原始数据)的问题。
【解决方案2】:

扩展Brian B's answer

这可确保保存点名称是唯一的,并使用 SQL Server 2012 的新 TRY/CATCH/THROW 功能。

DECLARE @mark CHAR(32) = replace(newid(), '-', '');
DECLARE @trans INT = @@TRANCOUNT;

IF @trans = 0
    BEGIN TRANSACTION @mark;
ELSE
    SAVE TRANSACTION @mark;

BEGIN TRY
    -- do work here

    IF @trans = 0
        COMMIT TRANSACTION @mark;
END TRY
BEGIN CATCH
    IF xact_state() = 1 OR (@trans = 0 AND xact_state() <> 0) ROLLBACK TRANSACTION @mark;
    THROW;
END CATCH

【讨论】:

  • 我已经有一段时间没有回到这篇文章了,但我喜欢这个模板,你可以在下一个查询中逐字重复使用。很好的增强。
  • 我在 MSDN 上看到了将 begin transaction 语句放在 try 块中的建议。在这种模式下这样做会导致一些问题还是完全安全?
  • 我对 catch 块中的 if 语句感到困惑。如果 xact state = -1,为什么要回滚事务。不应该是-1吗?
  • 我遇到的问题现已解决。在上面的模板中,无论 trans 变量如何,我的代码都是 COMMIT TRANSACTION 标记。它大部分时间都有效,但并非总是如此。只是想根据您的模板想知道我们是否应该在未嵌套的情况下提交事务,在嵌套的情况下不提交事务??
【解决方案3】:

我在我的存储过程中使用过这种类型的事务管理器:

    CREATE PROCEDURE Ardi_Sample_Test  
        @InputCandidateID INT  
    AS  
        DECLARE @TranCounter INT;  
        SET @TranCounter = @@TRANCOUNT;  
        IF @TranCounter > 0  
            SAVE TRANSACTION ProcedureSave;  
        ELSE  
            BEGIN TRANSACTION;  
        BEGIN TRY  

            /*
            <Your Code>
            */

            IF @TranCounter = 0  
                COMMIT TRANSACTION;  
        END TRY  
        BEGIN CATCH  
            IF @TranCounter = 0  
                ROLLBACK TRANSACTION;  
            ELSE  
                IF XACT_STATE() <> -1  
                    ROLLBACK TRANSACTION ProcedureSave;  

            DECLARE @ErrorMessage NVARCHAR(4000);  
            DECLARE @ErrorSeverity INT;  
            DECLARE @ErrorState INT;  
            SELECT @ErrorMessage = ERROR_MESSAGE();  
            SELECT @ErrorSeverity = ERROR_SEVERITY();  
            SELECT @ErrorState = ERROR_STATE();  

            RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);  
        END CATCH  
    GO  

【讨论】:

  • Microsoft 同意这是推荐的方法。 Reference
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多