2011-10-31 9 views
7

Próbujemy zrobić pośredni transakcję zagnieżdżenia za pomocą poniższego kodu .NET 3.5, SQL Server 2005 &używając TransactionScope: System.Transactions.TransactionAbortedException: Transakcja została przerwana

MSDN mówi, że podczas korzystania TransactionScope, transakcja jest eskalowana, ilekroć aplikacja otwiera drugie połączenie (nawet do tej samej bazy danych) w ramach Transakcji.

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

Zdarza się, że transakcja nie powiedzie się, że nie promuje do DTC, i jesteśmy coraz dalej jako wewnętrznej śladu stosu,

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)  

Czy ktoś może mi pomóc dowiedzieć się, jakie są tego powody niepowodzenie?

+0

Czy próbowałeś zamknąć połączenie? Czasami pojawiają się takie błędy, gdy połączenie jest już otwarte. Mogę być w błędzie. –

+0

Czy próbowałeś dodać *; MultipleActiveResultSets = True * w ciągu połączenia –

Odpowiedz

0

Mogę zaproponować ci lepszy sposób na osiągnięcie celu. powinna istnieć pojedyncza transakcja dla 2 połączeń DB na połączenie.

powinno być jak

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

Nie możesz powiedzieć, że to lepsze rozwiązanie. Co się stanie, jeśli nie możesz zmienić metod akceptowania połączenia? Co jeśli metody znajdują się w różnych obiektach? Co jeśli te metody mają już zbyt wiele parametrów? To też jest brzydkie. –

3

Jeśli używasz TransactionScope i wam

  • otwarte więcej niż jednego połączenia z bazą danych i
  • są podłączenia do serwera SQL 2005 server

Transakcja zostanie przekazana do DTC. Zaznacz to inne tak pytanie: TransactionScope automatically escalating to MSDTC on some machines?

Rozwiązaniem jest albo:

  • użycie SQL Server 2008 lub
  • Zastosowanie SqlTransaction zamiast TransactionScope podobnie jak dawny odpowiedź sugeruje:

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