执行之后的事务计数表示 BEGIN 和 COMMIT 语句的数量不匹配.上一个计数 = 1,当前计数 = 0



我有一个Insert存储过程,它将向Table1提供数据并从Table1获取Column1值,并调用第二个存储过程,该过程将馈送 Table2。

但是当我调用第二个存储过程时:

Exec USPStoredProcName

我收到以下错误:

执行之后的事务计数表示 BEGIN 和 COMMIT 语句的数量不匹配。上一个计数 = 1,当前计数 = 0。

我已经阅读了其他此类问题的答案,但无法找到提交计数的确切位置。

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

我建议您查看异常处理和嵌套事务,其中显示了可用于嵌套事务和异常的模式:

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

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

return
commit

而不是

commit
return   

在一个存储过程中。

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

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

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

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

与 TRY/CATCH 结合使用时,这可能会导致您描述的错误。在此处查看更多内容。

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

我发现我必须使用 2 个存储过程,一个是"worker",一个是带有 try/catch 的包装器,其逻辑类似于 Remus Rusanu 概述的逻辑。worker catch 用于处理"正常"故障,包装器 catch 用于处理编译失败错误。

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

不受 TRY 影响的错误...捕获构造

当以下类型的错误发生在与 TRY 相同的执行级别时,CATCH 块不会处理这些错误。CATCH 构造:编译错误,

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

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

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

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

对我来说,经过广泛的调试,修复是一个简单的缺失抛出; 回滚后捕获中的语句。没有它,这个丑陋的错误消息就是你最终得到的。

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

我有同样的错误消息,我的错误是我在提交事务行的末尾有一个分号

避免使用

RETURN

使用时的语句

BEGIN TRY
... 
END TRY
BEGIN CATCH
...
END CATCH

BEGIN, COMMIT & ROLLBACK

SQL 存储过程中的语句

在从事务中省略此语句后,我遇到了一次此错误。

COMMIT TRANSACTION [MyTransactionName]

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

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

Begin
Begin
-- your query here
End
commit

而不是

Begin Transaction
Begin
-- your query here
End
commit

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

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

就我而言,我不小心在查询中有一个 BEGIN TRAN 语句

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

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

此消息的确切原因是 SQL Server 暗示的规则:在过程执行的开始和结束时,事务计数应相同。换句话说,一个程序;

  • 不应提交/回滚未启动的事务。在这种情况下,异常消息中显示的先前计数将大于零,当前计数为零。防止这种情况的最佳方法是在执行开始时捕获事务计数 (@@TRANCOUNT),并且仅在事务语句为零时才使用事务语句。下面的示例过程是针对此类错误的最简单的"安全"结构。如果在现有事务中调用此过程,则它不会开始新事务,也不会尝试提交或回滚"继承"事务。相反,它只是将相同的错误重新抛向调用方上下文。这也是保留错误的真实源过程的好做法。
  • 应该在执行结束之前决定它启动的事务的命运(提交或回滚)。在这种情况下,当前计数将大于以前的计数。

我强烈建议您仔细阅读 Erland Sommarskog 在 SQL Server 中的错误和事务处理

<小时 />
create or alter proc sp_err266
as
begin
set nocount on
set xact_abort on
declare @trancount int = @@trancount
if @trancount = 0
begin tran
begin try
raiserror('Raise an unexpected error...', 16, 1);

if XACT_STATE() = 1 and @trancount = 0
commit;
end try
begin catch
if XACT_STATE() <> 0 and @trancount = 0
rollback;
else
throw;
end catch
end

如果您的代码结构如下:

SELECT 151
RETURN -151

然后使用:

SELECT 151
ROLLBACK
RETURN -151

对我来说,两个开始事务和多个回滚事务导致此问题。

------------------------------------------------------------
BEGIN TRANSACTION
-- BEGING TRANSACTION
call of stored procedure   -- ROLLBACK TRANASCTION
-- ROLLBACK TRANSACTION
ROLLBACK TRANSACTION
-----------------------------------------------------------

它只能回滚一次,不会有多个回滚语句,还可以检查导致问题的返回语句。

在嵌套过程中,应谨慎使用回滚,此处详细说明 https://stackoverflow.com/a/74479802/6204480

最新更新