【问题标题】:TransactionScope has aborted transaction before disposalTransactionScope 在处置前中止了事务
【发布时间】:2014-02-14 05:37:30
【问题描述】:

当使用 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

【问题讨论】:

    标签: c# sql transactions


    【解决方案1】:

    scope.Dispose() 可能会抛出 TransactionAborted 异常,即使 scope.Complete() 已被调用。例如,一些存储过程足够聪明地处理异常并使用T-SQL TRY/CATCH 构造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
    }
    

    不用担心处理TransactionScope。 scope.Dispose 在抛出 TransactionAborted 异常之前执行任何必要的清理工作。

    【讨论】:

      【解决方案2】:

      我不使用存储过程或特定于 SQL 的 try/catch,所以我的情况略有不同,但我得到了帖子中提到的完全相同的事务中止异常。我发现如果我在主 TransactionScope 内的某个地方有一个 SELECT,这将导致事务提交,尽管我不知道为什么。我有一个案例,为了在数据库中创建一个对象,它首先检查以确保该对象不存在于一个 SELECT 中,然后在调用 Dispose 时发生中止异常。我查看了内部异常,它说事务试图在没有开始的情况下提交。我终于尝试将我的 SELECT 包装在一个 Suppressed 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
      

      我希望这可以帮助其他可能在不使用存储过程的情况下获得此异常的人。

      【讨论】:

        【解决方案3】:

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

        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();
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-29
          • 1970-01-01
          • 2020-04-24
          • 1970-01-01
          • 1970-01-01
          • 2011-02-11
          相关资源
          最近更新 更多