10

以下のコード、.NET 3.5、および SQL Server 2005 を使用して、間接的なネスティング トランザクションを実行しようとしています。

MSDN によると、TransactionScope を使用すると、アプリケーションがトランザクション内で (同じデータベースへの接続であっても) 2 つ目の接続を開くたびに、トランザクションがエスカレートされます。

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)    

この失敗の理由を理解するのを手伝ってくれる人はいますか?

4

2 に答える 2

5

TransactionScope を使用している場合:

  • データベースへの複数の接続を開き、
  • SQL Server 2005 サーバーに接続しています

トランザクションは DTC にエスカレートされます。この他の SO の質問を確認してください:一部のマシンで TransactionScope が MSDTC に自動的にエスカレートしますか?

解決策は次のいずれかです。

  • SQL Server 2008 または
  • 前の回答が示唆するように、 TransactionScope の代わりに SqlTransaction を使用します。

    using (var conn = new SqlConnection(connectionString))
    {  
        using (var tx = conn.BeginTransaction())
        {
            FirstMethod(conn);
            SecondMethod(conn);
            tx.Commit();
        }
    }
    
于 2011-12-30T16:05:41.860 に答える
0

私はあなたにあなたの目標を達成するためのより良い方法を提案することができます。接続ごとに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()
        {
        }
    }
}
于 2011-10-31T05:06:45.540 に答える