C# TransactionScope在处置前已中止事务

C# TransactionScope在处置前已中止事务,c#,sql,transactions,C#,Sql,Transactions,使用TransactionScope时,如果内部执行的代码回滚事务,则父事务也会回滚。这对我有好处。但在处理该作用域时,它会抛出一个异常,这意味着事务已经回滚并中止。 那么,什么是正确的方法来处理这个问题并正确地处理范围呢 using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew)) { using (var conn =

使用TransactionScope时,如果内部执行的代码回滚事务,则父事务也会回滚。这对我有好处。但在处理该作用域时,它会抛出一个异常,这意味着事务已经回滚并中止。 那么,什么是正确的方法来处理这个问题并正确地处理范围呢

    using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
    {
                    using (var conn = GetConnection())
                    {
                            string query = 
              @"some query that may contain transaction itself 
              or some SP whith transaction included"

                            using (var command = new SqlCommand(query, conn))
                                command.ExecuteNonQuery();
                        }
                    }
                    scope.Complete();
    } // Exception here

如果内部查询引发异常,则不会执行scope.Complete()行。 请参考下面的链接。。我也对您的查询做了一些更改。我希望它对你有用。

scope.Dispose()
即使调用了
scope.Complete()。例如,一些存储过程足够聪明,可以使用
T-SQL TRY/CATCH
construct
w/o
向调用者抛出异常来处理异常和中止T-SQL脚本内的事务。 所以我认为我建议的最安全的方法如下:

try
{
    using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
    {
        try
        {
            using (var conn = GetConnection())
            {
                string query = 
                @"some query that may contain transaction itself 
                or some SP whith transaction included"

                using (var command = new SqlCommand(query, conn))
                command.ExecuteNonQuery();
            }
        }
        catch (SqlException ex)
        {
            // log SQL Exception, if any
            throw;  // re-throw exception
        }

        scope.Complete();
    }
}
catch (TransactionAbortedException ex)
{
    // we can get here even if scope.Complete() was called.
    // log TransactionAborted exception if necessary
}

不要担心如何处理
事务范围
。scope.Dispose在抛出
TransactionBorted
异常之前执行任何必要的清理操作。

我不使用存储过程或特定于SQL的try/catch,因此我的情况略有不同,但我得到了与帖子中提到的事务中止异常完全相同的异常。我发现,如果我在主TransactionScope中的某个地方有一个SELECT,这将导致事务提交,尽管我不知道为什么。我遇到过这样一种情况,为了在数据库中创建一个对象,它首先检查以确保该对象不存在SELECT,然后在调用Dispose时发生异常中止。我查看了内部异常,它表示事务试图在没有开始的情况下提交。最后,我尝试将我的选择包装在一个被抑制的TransactionScope中,然后它成功了。因此:

using(TransactionScope tx = new TransactionScope()) 
{ 
  //UPDATE command for logging that I want rolled back if CREATE fails

  using(TransactionScope tx2 = new TransactionScope(TransactionScopeOption.Suppress)) 
  { 
    // SELECT command
  } 

  //If not exists logic
  //CREATE command
} //Used to error here, but not with the SELECT Suppressed
我希望这能帮助其他可能在不使用存储过程的情况下获得此异常的人

using(TransactionScope tx = new TransactionScope()) 
{ 
  //UPDATE command for logging that I want rolled back if CREATE fails

  using(TransactionScope tx2 = new TransactionScope(TransactionScopeOption.Suppress)) 
  { 
    // SELECT command
  } 

  //If not exists logic
  //CREATE command
} //Used to error here, but not with the SELECT Suppressed