我一直试图让这个工作一段时间。
我有一个存储过程(我们称之为SPA
)由另一个开发人员编写,该编译器对数据库执行多次插入,并且所有这些插入都包装在存储过程中的事务中。我还有另一个不使用事务的存储过程(称之为SPB
)。
从我的.NET代码中,我需要在事务中包装这两个存储过程,以确保如果SPB
不成功,则回滚所有SPA
。不幸的是,这对我不起作用。我得到的错误是:
无法回滚销售。未找到该名称的交易或保存点 EXECUTE之后的事务计数表示BEGIN和COMMIT语句的数量不匹配。先前的计数= 1,当前计数= 2.
我已确认在退出之前始终在ROLLBACK
内调用COMMIT
或SPA
。我的.NET代码非常简单:
try {
conn.Open();
trans = conn.BeginTransaction();
prod.Connection = conn;
prod.Transaction = trans;
// Execute SPA
// Execute SPB
} catch (Exception ex) {
trans.Rollback();
} finally {
conn.Close();
}
如果我将.NET从等式中取出并简单地使用SSMS来封装SP,那么我会得到相同的错误消息。
BEGIN TRAN
DECLARE @return_value int
EXEC @return_value = [dbo].[spSPA] [...]
SELECT 'Return Value' = @return_value
COMMIT TRAN
有什么想法吗?
编辑:
SPA
看起来像:
BEGIN TRY
BEGIN TRAN SALE
IF SomeCondition
DoSomething
ELSE
ROLLBACK TRAN SALE
RETURN 100
IF SomeCondition
DoSomething
ELSE
ROLLBACK TRAN SALE
RETURN 200
...
COMMIT TRAN SALE
RETURN 0
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0
ROLLBACK TRAN SALE
END CATCH
答案 0 :(得分:1)
我终于发现了我的问题。我收到警告Cannot roll back SALE. No transaction or savepoint of that name was found.
,因为如果你有一个嵌套事务,在回滚时你必须指定最外层事务的名称。当然我不知道该交易的名称是什么。
解决方法是使用TechNet中所述的保存点。因此,我必须检查是否存在现有事务,如果存在,则使用保存点。否则,创建我自己的:
DECLARE @TRANCOUNT int
SET @TRANCOUNT = @@TRANCOUNT
IF @TRANCOUNT = 0 BEGIN TRAN
ELSE SAVE TRANSACTION SALE