【问题标题】:using TransactionScope : System.Transactions.TransactionAbortedException: The transaction has aborted使用 TransactionScope:System.Transactions.TransactionAbortedException:事务已中止
【发布时间】:2011-10-31 04:37:38
【问题描述】:

我们正在尝试使用以下代码进行间接嵌套事务,.NET 3.5 和 SQL Server 2005。

MSDN 说,在使用 TransactionScope 时,只要应用程序在 Transaction 中打开第二个连接(甚至是同一个数据库),事务就会升级。

void RootMethod()
{
   using(TransactionScope scope = new TransactionScope())
   {
      /* Perform transactional work here */
      FirstMethod();
      SecondMethod();
      scope.Complete();
   }
 }

void FirstMethod()
{
    using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
   {
     using (SqlConnection conn1 = new SqlConnection("Data Source=(local);Initial Catalog=Northwind;Integrated Security=SSPI")) 
       {
     string insertString = @"
             insert into Categories
             (CategoryName, Description)
             values ('Laptop1', 'Model001')";
         conn1.Open();
         SqlCommand cmd = new SqlCommand(insertString, conn1);
         cmd.ExecuteNonQuery();
        }
      scope.Complete();
    }
 }

 void SecondMethod()
 {
    using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
   {
       using (SqlConnection conn2 = new SqlConnection("Data Source=(local);Initial Catalog=Northwind;Integrated Security=SSPI")) 
       {
     string insertString = @"
             insert into Categories
             (CategoryName, Description)
             values ('Laptop2', 'Model002')";

         conn2.Open();  //Looks like transactionabortedException is happening here
         SqlCommand cmd = new SqlCommand(insertString, conn2);
         cmd.ExecuteNonQuery();
        }
        scope.Complete();
    }
  }

有时,事务失败,没有升级到 DTC,我们得到以下作为内部堆栈跟踪,

System.Transactions.TransactionAbortedException: The transaction has aborted. ---> 
System.Transactions.TransactionPromotionException: Failure while attempting to promote transaction. ---> 
System.InvalidOperationException: The requested operation cannot be completed because the connection has been broken.     
at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransaction(TransactionRequest transactionRequest, String name, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)     
at System.Data.SqlClient.SqlDelegatedTransaction.Promote()     --- End of inner exception stack trace ---     
at System.Data.SqlClient.SqlDelegatedTransaction.Promote()     
at System.Transactions.TransactionStatePSPEOperation.PSPEPromote(InternalTransaction tx)     
at System.Transactions.TransactionStateDelegatedBase.EnterState(InternalTransaction tx)     
--- End of inner exception stack trace ---     
at System.Transactions.TransactionStateAborted.CreateAbortingClone(InternalTransaction tx)     
at System.Transactions.DependentTransaction..ctor(IsolationLevel isoLevel, InternalTransaction internalTransaction, Boolean blocking)     
at System.Transactions.Transaction.DependentClone(DependentCloneOption cloneOption)     
at System.Transactions.TransactionScope.SetCurrent(Transaction newCurrent)     
at System.Transactions.TransactionScope.PushScope()     
at System.Transactions.TransactionScope..ctor(TransactionScopeOption scopeOption)    

谁能帮我找出失败的原因?

【问题讨论】:

  • 你试过关闭连接吗?当连接已经打开时,有时我确实会收到此类错误。可能我错了。
  • 您是否尝试在连接字符串中添加 ;MultipleActiveResultSets=True

标签: c# .net system.transactions


【解决方案1】:

如果您使用 TransactionScope 并且您:

  • 打开多个到数据库的连接并
  • 正在连接到 SQL Server 2005 服务器

交易将升级到 DTC。检查其他 SO 问题:TransactionScope automatically escalating to MSDTC on some machines?

解决办法是:

  • 使用 SQL Server 2008 或
  • 使用 SqlTransaction 而不是 TransactionScope 就像前一个答案建议的那样:

    using (var conn = new SqlConnection(connectionString))
    {  
        using (var tx = conn.BeginTransaction())
        {
            FirstMethod(conn);
            SecondMethod(conn);
            tx.Commit();
        }
    }
    

【讨论】:

    【解决方案2】:

    我可以向您提出更好的方法来实现您的目标。 每个连接应该有一个用于 2 个 DB 调用的事务。

    应该是这样的

    using (SqlConnection conn1 = new SqlConnection("Data Source=(local);Initial Catalog=Northwind;Integrated Security=SSPI"))
    { 
        using (conn1.BeginTransaction()
        {
            try
            {
                FirstMethod(Conn1);
                SecondMethod(Conn2);
            }
            catch()
            {
            }
        }
    }
    

    【讨论】:

    • 你不能说这是更好的解决方案。如果您无法更改方法以接受连接怎么办?如果方法在不同的对象中怎么办?如果这些方法已经有太多参数怎么办?这也很丑。
    猜你喜欢
    • 2019-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多