我有一个存储过程,它本身按顺序调用其他存储过程的列表:
CREATE PROCEDURE [dbo].[prSuperProc]
AS
BEGIN
EXEC [dbo].[prProc1]
EXEC [dbo].[prProc2]
EXEC [dbo].[prProc3]
--etc
END
但是,我的表中有时会产生一些奇怪的结果,由prProc2生成,这取决于prProc1生成的结果。如果我按顺序手动执行prProc1,prProc2,prProc3,那么一切都很好。看来,当我运行顶级过程时,在Proc1完成之前正在执行Proc2并将其结果提交给db。它并不总是出错,但是当Proc1的执行时间很长时(在这种情况下~10秒),它似乎出错了。
如何更改prSuperProc以使每个过程仅在前面的过程完成并提交后才执行?交易?
修改额外的详细信息:
我的数据库中有一个表,其中一列默认为null。 prProc1在此表上执行一组更新语句以填充此列。然后,prProc2根据此列中的值将摘要数据插入到辅助表中。
当我运行超级过程时,我(有时)看到的是第一个表具有由prProc1正确计算的结果,但是prProc2已经生成结果,好像该列全部为空。如果我然后手动运行prProc2,则会正确生成摘要数据。
答案 0 :(得分:4)
答案 1 :(得分:2)
对于prSuperProc
的每次调用,它们将以连续方式运行,1然后是下一个,然后是下一个。但是,如果多个用户都在调用prSuperProc
,那么您将执行用户1的prProc1-prProc2 + prProc3和用户2的prProc1-prProc2 + prProc3的交错执行。
可能是这样的:
user1 calls prSuperProc
user1 prProc1 is called
user2 calls prSuperProc
user1 prProc2 is called
user2 prProc1 is called
user1 prProc3 is called
user2 prProc2 is called
user2 prProc3 is called
这实际上取决于您的程序中发生了什么,有多少并发用户以及他们正在更改和/或锁定哪些行
修改强> 你可以尝试这个来解决问题:
CREATE PROCEDURE [dbo].[prSuperProc]
AS
BEGIN TRY
BEGIN TRANSACTION
EXEC [dbo].[prProc1]
EXEC [dbo].[prProc2]
EXEC [dbo].[prProc3]
--etc
COMMIT
END TRY
BEGIN CATCH
IF XACT_STATE()!=0
BEGIN
ROLLBACK TRANSACTION
END
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_LINE() AS ErrorLine
,ERROR_MESSAGE() AS ErrorMessage
--will echo back the complete original error message
DECLARE @ErrorMessage nvarchar(400), @ErrorNumber int, @ErrorSeverity int, @ErrorState int, @ErrorLine int
SELECT @ErrorMessage = N'Error %d, Line %d, Message: '+ERROR_MESSAGE(),@ErrorNumber = ERROR_NUMBER(),@ErrorSeverity = ERROR_SEVERITY(),@ErrorState = ERROR_STATE(),@ErrorLine = ERROR_LINE()
RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorNumber,@ErrorLine)
END CATCH
GO
通过围绕所有事务使用事务,它将尝试锁定任何并发用户处理相同数据。使用TRY-CATCH将尝试捕获一个过程中可能发生的任何错误,并防止下一个过程运行。
答案 2 :(得分:2)
我遇到了同样的问题(当时正在维护产品)并且我通过取出最外层的proc并执行最顶层的proc来修复它。那个proc会执行依赖它的proc等等。它在B ***中很痛苦,但它确实有效。
HTH