我有一个Insert
存储过程,该存储过程将向其馈送数据Table1
并从中获取Column1
值,Table1
并调用第二个存储过程,该第二个存储过程将馈入Table2。
但是当我将第二个存储过程称为:
Exec USPStoredProcName
我收到以下错误:
EXECUTE之后的事务计数指示BEGIN和COMMIT语句的数量不匹配。先前计数= 1,当前计数= 0。
我已经阅读了其他此类问题的答案,无法找到确切的提交计数被弄乱的地方。
我有一个Insert
存储过程,该存储过程将向其馈送数据Table1
并从中获取Column1
值,Table1
并调用第二个存储过程,该第二个存储过程将馈入Table2。
但是当我将第二个存储过程称为:
Exec USPStoredProcName
我收到以下错误:
EXECUTE之后的事务计数指示BEGIN和COMMIT语句的数量不匹配。先前计数= 1,当前计数= 0。
我已经阅读了其他此类问题的答案,无法找到确切的提交计数被弄乱的地方。
Answers:
如果您有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
xact_abort on
?
我也有这个问题。对我来说,原因是我在做
return
commit
代替
commit
return
在一个存储过程中。
这通常在事务启动且未提交或未回滚时发生。
万一存储过程中出现错误,这可以锁定数据库表,因为在缺少异常处理的情况下由于某些运行时错误而导致事务未完成,因此可以使用以下异常处理。 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
如果您的存储过程在打开事务后遇到编译失败(例如,找不到表,无效的列名),也会发生这种情况。
我发现我必须使用2个存储过程,一个是“工作者”一个,另一个是使用try / catch的包装器,两者的逻辑都类似于Remus Rusanu概述的逻辑。辅助捕获用于处理“常规”故障,而包装捕获用于处理编译故障错误。
https://msdn.microsoft.com/zh-CN/library/ms175976.aspx
受TRY…CATCH构造影响的错误
当以下几种类型的错误与TRY…CATCH构造在相同的执行级别上发生时, CATCH块将不对其进行处理:
- 编译错误(例如语法错误)会阻止批处理运行。
- 在语句级重新编译期间发生的错误,例如由于延迟的名称解析而在编译后发生的对象名称解析错误。
希望这可以帮助其他人节省几个小时的调试...
就我而言,该错误是由中的引起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
我有同样的错误信息,我的错误是我在COMMIT TRANSACTION行的末尾有一个分号
这也可能取决于您从C#代码调用SP的方式。如果SP返回某个表类型值,则使用ExecuteStoreQuery调用SP,如果SP不返回任何值,则使用ExecuteStoreCommand调用SP。
避免使用
RETURN
使用时的声明
BEGIN TRY
...
END TRY
BEGIN CATCH
...
END CATCH
和
BEGIN, COMMIT & ROLLBACK
SQL存储过程中的语句