EXECUTE 之后的事务计数表明 BEGIN 和 COMMIT 语句的数量不匹配。先前计数 = 1,当前计数 = 0
Posted
技术标签:
【中文标题】EXECUTE 之后的事务计数表明 BEGIN 和 COMMIT 语句的数量不匹配。先前计数 = 1,当前计数 = 0【英文标题】:Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0 【发布时间】:2014-03-22 17:10:03 【问题描述】:我有一个Insert
存储过程,它将向Table1
提供数据,并从Table1
获取Column1
值,然后调用第二个存储过程来提供给Table2。
但是当我调用第二个存储过程为:
Exec USPStoredProcName
我收到以下错误:
。
我已阅读其他此类问题的答案,但无法找到提交计数究竟在哪里弄乱了。
【问题讨论】:
您的程序中有任何 TRY/CATCH 块吗? 是的,我有 TRY / CATCH 块 【参考方案1】:对我来说,问题是我忘记在事务中 SP 调用的一些输出参数之后添加 output
关键字。
【讨论】:
【参考方案2】:避免使用
RETURN
使用时的声明
BEGIN TRY
...
END TRY
BEGIN CATCH
...
END CATCH
和
BEGIN, COMMIT & ROLLBACK
SQL 存储过程中的语句
【讨论】:
【参考方案3】:在我的例子中,错误是由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
【讨论】:
【参考方案4】:这还取决于您从 C# 代码调用 SP 的方式。如果 SP 返回某个表类型值,则使用 ExecuteStoreQuery 调用 SP,如果 SP 没有返回任何值,则使用 ExecuteStoreCommand 调用 SP
【讨论】:
【参考方案5】:确保在同一过程/查询中没有多个事务,其中一个或多个未提交。
在我的例子中,我不小心在查询中有一个 BEGIN TRAN 语句
【讨论】:
【参考方案6】:我有同样的错误信息,我的错误是我在 COMMIT TRANSACTION 行的末尾有一个分号
【讨论】:
就这么简单。另外,我的案例需要一个“ROLLBACK”语句,以防 SP 无法完全执行。仅用于关闭/结束交易。【参考方案7】:在我看来,接受的答案在大多数情况下是矫枉过正的。
错误的原因通常是错误中明确说明的 BEGIN 和 COMMIT 不匹配。这意味着使用:
Begin
Begin
-- your query here
End
commit
而不是
Begin Transaction
Begin
-- your query here
End
commit
在 Begin 之后省略 Transaction 会导致此错误!
【讨论】:
【参考方案8】:如果您的代码结构类似于:
SELECT 151
RETURN -151
然后使用:
SELECT 151
ROLLBACK
RETURN -151
【讨论】:
【参考方案9】:对我来说,经过大量调试后,修复是一个简单的丢包;回滚后的 catch 语句。没有它,你最终会得到这个丑陋的错误消息。
begin catch
if @@trancount > 0 rollback transaction;
throw; --allows capture of useful info when an exception happens within the transaction
end catch
【讨论】:
【参考方案10】:如果您的存储过程在打开事务后遇到编译失败(例如未找到表、列名无效),也会发生这种情况。
我发现我必须使用 2 个存储过程,一个是“worker”,一个是包装器,两者都具有类似于 Remus Rusanu 概述的逻辑。 worker catch 用于处理“正常”失败,wrapper catch 用于处理编译失败错误。
https://msdn.microsoft.com/en-us/library/ms175976.aspx
不受 TRY…CATCH 构造影响的错误
以下类型的错误不会由 CATCH 块处理当它们发生在与 TRY...CATCH 构造相同的执行级别时:
编译错误,例如语法错误,导致批处理无法运行。 语句级重新编译期间发生的错误,例如由于延迟名称解析而在编译后发生的对象名称解析错误。
希望这可以帮助其他人节省几个小时的调试时间...
【讨论】:
谢谢贾斯汀。很好的观察。在我的情况下,我在更新中进行聚合,它在 SP 保存期间不会产生编译错误,但确实是无效的语法 - “聚合可能不会出现在 UPDATE 语句的集合列表中”【参考方案11】:在我的事务中省略此语句后,我遇到过一次此错误。
COMMIT TRANSACTION [MyTransactionName]
【讨论】:
【参考方案12】:请注意,如果您使用嵌套事务,ROLLBACK 操作会回滚所有嵌套事务,包括最外层的事务。
这可能与 TRY/CATCH 结合使用,导致您描述的错误。查看更多here。
【讨论】:
【参考方案13】:我也有这个问题。对我来说,原因是我在做
return
commit
而不是
commit
return
在一个存储过程中。
【讨论】:
@seguso - 这很有帮助。谢谢你的分享。有时,一些如此简单的东西就隐藏在尘埃之下。发生在他们中最好的人身上。 这对我来说是个问题,但不太明显,因为我们通过数据访问层将多个存储过程调用包装在一个大事务中——因此,仅查看存储过程就无法判断存在一笔交易。如果您遇到此问题,请确保存储过程本身之外没有任何东西正在创建事务。如果有,那么您可能根本无法在存储过程中使用 return 语句。 这是我,我有一个事务并且在我的提交事务之前在 if/else 语句中返回【参考方案14】:这通常发生在事务启动且未提交或未回滚时。
如果错误出现在您的存储过程中,这可以锁定数据库表,因为在没有异常处理的情况下由于一些运行时错误导致事务未完成 您可以使用如下所示的异常处理。 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
【讨论】:
如果是这种情况,引用的问题/答案可能意味着这个问题应该被标记为重复并关闭【参考方案15】:如果您有一个 TRY/CATCH 块,那么可能的原因是您正在捕获事务中止异常并继续。在 CATCH 块中,您必须始终检查 XACT_STATE()
并处理适当的中止和不可提交(注定)的事务。如果你的调用者启动了一个事务并且被调用者遇到了死锁(它中止了事务),那么被调用者将如何与调用者沟通事务被中止并且它不应该继续“照常营业”?唯一可行的方法是重新引发异常,强制调用者处理这种情况。如果你默默吞下一个中止的事务,而调用者继续假设仍在原始事务中,那么只有混乱可以确保(你得到的错误是引擎试图保护自己的方式)。
我建议您查看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
【讨论】:
感谢您的帮助。通过使用 Raiserror 我发现了问题。这是关于尝试将 NULL 值插入 NOT NULL 字段 但是约束检查验证不会中止事务。你是明确回滚,还是使用xact_abort on
?
我明确回滚
我已经尝试过这种模式,但它仍然不起作用 - 当我有一个外部事务时,这个模式会创建一个保存点,并且在发生严重错误(不可提交的事务)的情况下回滚外部事务 - 这仍然会导致进入程序前@@trancount = 1,退出程序时@@trancount = 0
我认为 CATCH 中的这一点是错误的:if @xstate = -1 rollback;
看看这个MSDN example,我们应该不回滚整个事务,除非有不 一个外部事务(也就是说,除非我们做了begin tran
)。我认为如果我们开始交易,该程序应该只有rollback
,这将解决@sparrow的问题。以上是关于EXECUTE 之后的事务计数表明 BEGIN 和 COMMIT 语句的数量不匹配。先前计数 = 1,当前计数 = 0的主要内容,如果未能解决你的问题,请参考以下文章
EXECUTE 之后的事务计数表明 BEGIN 和 COMMIT 语句的数量不匹配。先前计数 = 1,当前计数 = 0