在事务中包装事务处理的存储过程

时间:2013-11-14 23:49:47

标签: .net sql sql-server

我一直试图让这个工作一段时间。

我有一个存储过程(我们称之为SPA)由另一个开发人员编写,该编译器对数据库执行多次插入,并且所有这些插入都包装在存储过程中的事务中。我还有另一个不使用事务的存储过程(称之为SPB)。

从我的.NET代码中,我需要在事务中包装这两个存储过程,以确保如果SPB不成功,则回滚所有SPA。不幸的是,这对我不起作用。我得到的错误是:

  

无法回滚销售。未找到该名称的交易或保存点   EXECUTE之后的事务计数表示BEGIN和COMMIT语句的数量不匹配。先前的计数= 1,当前计数= 2.

我已确认在退出之前始终在ROLLBACK内调用COMMITSPA。我的.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

1 个答案:

答案 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