EXECUTE之后的事务计数表示BEGIN和COMMIT语句的数量不匹配。先前的计数= 1,当前计数= 0

时间:2014-02-21 09:23:00

标签: sql sql-server-2012 sqlexception

我有一个插入存储过程,它将数据提供给Table1并从Table1获取Column1值并调用第二个存储过程,该过程将为Table2提供数据。

但是当我把第二个存储过程称为:

Exec USPStoredProcName

它给出了如下错误:

  

EXECUTE之后的事务计数表示BEGIN和COMMIT语句的数量不匹配。先前的计数= 1,当前计数= 0。

我已经阅读了其他类似问题的答案,但我无法找到提交计数到底搞砸的地方。

15 个答案:

答案 0 :(得分:93)

如果你有一个TRY / CATCH块,那么可能的原因是你正在捕获一个事务中止异常并继续。在CATCH块中,您必须始终检查XACT_STATE()并处理适当的中止和不可拒绝(注定)事务。如果你的调用者启动了一个事务并且calee命中了一个死锁(它中止了事务),那么被调用者如何与调用者通信该事务被中止并且它不应该继续“照常营业”?唯一可行的方法是重新引发异常,强制调用者处理这种情况。如果你静默地吞下一个中止的事务并且调用者继续假设仍然在原始事务中,那么只有混乱才能确保(并且你得到的错误就是引擎试图保护自己的方式)。

我建议你过去Exception handling and nested transactions,它显示了一个可以用于嵌套事务和例外的模式:

create procedure [usp_my_procedure_name]
as
begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        -- Do the actual work here

lbexit:
        if @trancount = 0
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
    end catch
end
go

答案 1 :(得分:46)

我也有这个问题。对我来说,原因是我在做什么

return
commit

而不是

commit
return   

在一个存储过程中。

答案 2 :(得分:15)

这通常在事务启动时发生,并且未提交或未回滚。

如果您的存储过程中出现错误,这可能会锁定数据库表,因为在没有异常处理的情况下由于某些运行时错误而未完成事务         您可以使用如下的异常处理。 SET XACT_ABORT

SET XACT_ABORT ON
SET NoCount ON
Begin Try 
     BEGIN TRANSACTION 
        //Insert ,update queries    
     COMMIT
End Try 
Begin Catch 
     ROLLBACK
End Catch

<强> Source

答案 3 :(得分:9)

请注意,如果使用嵌套事务,则ROLLBACK操作将回滚所有嵌套事务,包括最外层事务。

这可能与TRY / CATCH结合使用会导致您描述的错误。查看更多here

答案 4 :(得分:4)

就我而言,该错误是由RETURN内部的BEGIN TRANSACTION引起的。所以我有这样的东西:

Begin Transaction
 If (@something = 'foo')
 Begin
     --- do some stuff
     Return
 End
commit

,它必须是:

Begin Transaction
 If (@something = 'foo')
 Begin
     --- do some stuff
     Rollback Transaction ----- THIS WAS MISSING
     Return
 End
commit

答案 5 :(得分:2)

如果存储过程在打开事务后遇到编译失败(例如,找不到表,列名无效),也会发生这种情况。

我发现我必须使用2个存储过程a&#34; worker&#34;一个和一个包含try / catch的包装器,其逻辑类似于Remus Rusanu概述的逻辑。工人捕获用于处理&#34;正常&#34;失败和包装器catch来处理编译失败错误。

https://msdn.microsoft.com/en-us/library/ms175976.aspx

不受TRY ... CATCH构造影响的错误

  

当CATCH块与TRY ... CATCH构造处于相同的执行级别时,不会处理以下类型的错误:

  •   编译阻止批处理运行的错误,例如语法错误
  •   
  • 语句级重新编译期间发生的错误,例如由于延迟名称解析而在编译后发生的对象名称解析错误。

希望这有助于其他人节省几个小时的调试......

答案 6 :(得分:1)

我从事务中省略了这个语句后,我遇到了这个错误。

COMMIT TRANSACTION [MyTransactionName]

答案 7 :(得分:1)

我有相同的错误消息,我的错误是我在COMMIT TRANSACTION行结束时有一个分号

答案 8 :(得分:1)

这还取决于您从C#代码调用SP的方式。如果SP返回某个表类型值,则使用ExecuteStoreQuery调用SP,如果SP不返回任何值,则使用ExecuteStoreCommand调用SP

答案 9 :(得分:1)

避免使用

RETURN

使用时的声明

BEGIN TRY
    ... 
END TRY

BEGIN CATCH
    ...
END CATCH

BEGIN, COMMIT & ROLLBACK

SQL存储过程中的声明

答案 10 :(得分:1)

对我来说,问题是我忘记在事务中的 SP 调用的某些输出参数后面添加 output 关键字。

答案 11 :(得分:0)

经过大量调试后,对我来说修复是一个简单的失误;回滚后的语句中的语句。没有它,这个丑陋的错误信息就是你最终的结果。

begin catch
    if @@trancount > 0 rollback transaction;
    throw; --allows capture of useful info when an exception happens within the transaction
end catch

答案 12 :(得分:0)

在我看来,接受的答案在大多数情况下都是矫枉过正的。

错误的原因通常是错误明确指出的BEGIN和COMMIT不匹配。这意味着使用:

Begin
  Begin
    -- your query here
  End
commit

而不是

Begin Transaction
  Begin
    -- your query here
  End
commit

在开始后省略事务会导致此错误!

答案 13 :(得分:0)

请确保您在同一过程/查询中没有多个事务,其中一个或多个未提交。

就我而言,我不小心在查询中使用了BEGIN TRAN语句

答案 14 :(得分:-2)

如果您的代码结构类似于:

SELECT 151
RETURN -151

然后使用:

SELECT 151
ROLLBACK
RETURN -151