2013-04-29 24 views
13

Nasz zespół mam problem, który przejawia się jako:TransactionScope - Podstawowy dostawca nie powiódł się na EnlistTransaction. MSDTC jest przerwana

Podstawowym dostawcą zawiodły na EnlistTransaction; Nie można uzyskać dostępu do obiektu unieszkodliwionego .Object name: 'Transaction'.

enter image description here

co wydawało się pojawiać jak tylko zaczęliśmy używać TransactionScope do obsługi transakcji naszych aplikacji.

górna część stacktrace jest wychwytywana jako:

w System.Data.EntityClient.EntityConnection.EnlistTransaction (transakcja transakcja) w System.Data.Objects.ObjectContext.EnsureConnection() w System.Data.Objects.ObjectContext.ExecuteStoreCommand (ciąg CommandText, obiekt [] parametry) w Reconciliation.Models.BillLines.BillLines.Reconciliation.Interfaces.IBillLineEntities.ExecuteStoreCommand (ciąg, obiekt []) w Reconciliation.Models. Legacy.EntityDbEnvironment.Ex ecuteOracleSql (SQL String) w EntityDbEnvironment.cs: linia 41

Jednocześnie MSDTC dziennika jest aktualizowany, co mam ekstrakcji za pomocą instructions here:

pid=7060  ;tid=7908  ;time=04/29/2013-16:38:30.269 ;seq=136  ;eventid=TRANSACTION_BEGUN      ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e  ;"TM Identifier='(null)           '" ;"transaction has begun, description :'<NULL>'" 
pid=7060  ;tid=7908  ;time=04/29/2013-16:38:30.269 ;seq=137  ;eventid=RM_ENLISTED_IN_TRANSACTION    ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e  ;"TM Identifier='(null)           '" ;"resource manager #1002 enlisted as transaction enlistment #1. RM guid = 'defc4277-47a6-4cd9-b092-93a668e2097b'" 
pid=7060  ;tid=7908  ;time=04/29/2013-16:38:31.658 ;seq=138  ;eventid=RECEIVED_ABORT_REQUEST_FROM_BEGINNER  ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e  ;"TM Identifier='(null)           '" ;"received request to abort the transaction from beginner" 
pid=7060  ;tid=7908  ;time=04/29/2013-16:38:31.658 ;seq=139  ;eventid=TRANSACTION_ABORTING      ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e  ;"TM Identifier='(null)           '" ;"transaction is aborting" 
pid=7060  ;tid=7908  ;time=04/29/2013-16:38:31.658 ;seq=140  ;eventid=RM_ISSUED_ABORT       ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e  ;"TM Identifier='(null)           '" ;"abort request issued to resource manager #1002 for transaction enlistment #1" 
pid=7060  ;tid=7908  ;time=04/29/2013-16:38:31.658 ;seq=141  ;eventid=RM_ACKNOWLEDGED_ABORT     ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e  ;"TM Identifier='(null)           '" ;"received acknowledgement of abort request from the resource manager #1002 for transaction enlistment #1" 
pid=7060  ;tid=7908  ;time=04/29/2013-16:38:31.658 ;seq=142  ;eventid=TRANSACTION_ABORTED      ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e  ;"TM Identifier='(null)           '" ;"transaction has been aborted" 

Jak można zobaczyć RECEIVED_ABORT_REQUEST_FROM_BEGINNER sekund po RM_ENLISTED_IN_TRANSACTION został zalogowany.

Nie możemy zrozumieć, skąd pochodzi ten abortujący wniosek lub dlaczego został zgłoszony. SQL powodujący problem to prosty SELECT, który możemy wykonać bez problemu za pośrednictwem naszego klienta bazy danych.

Aplikacja działa większość czasu, tylko sporadycznie wyświetla ten problem.

Używamy Oracle 10.2.0.5.0 z Entity Framework.

UPDATE

Po poradę @Astrotrain skonfigurować rejestrowanie na System.Transactions. Ostateczna pozycja produkowana jest dosłownie odcięta w połowie drogi jednak:

.... 
<ApplicationData> 
<TraceData> 
<DataItem> 
<TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Information"> 
<TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/TransactionScopeCreated</TraceIdentifier> 
<Description>TransactionScope Created</Description> 
<AppDomain>BillLineGeneratorUI.exe</AppDomain> 
<ExtendedData xmlns="http://schemas.microsoft.com/2004/03/Transactions/TransactionScopeCreatedTraceRecord"> 
<TraceSource>[Base] 

Jak widać wyjątek rzeczywiście zapobiega wykończenie dziennika. Czego mogę się z tego nauczyć? Jakieś pomysły?

+0

Jak rozpocząć transakcje? Czy są zagnieżdżone? Czy możesz opublikować powiązany kod? Na razie wykluczam problemy związane z osiągalnością między dwiema instancjami MSDTC uczestniczącymi w transakcji. –

+3

Zdrap to. Zobacz: http://blogs.msdn.com/b/ajit/archive/2010/05/31/msdtc-oracle-10g-client-new-transaction-cannot-enlist-in-the-specified-transaction-coordinator .aspx –

+0

Przerwanie trwa więcej niż 1 sekundę po rozpoczęciu. Być może masz konfigurację czasu automatycznego/połączenia/polecenia/transakcji zdefiniowanego na 1 sekundę (lub 1000 ms) zamiast rozsądnego czasu. –

Odpowiedz

0

Mieliśmy również ten problem. Najlepszym sposobem na rozwiązanie wydaje się otworzyć nowe połączenie z bazą danych i po prostu zrobić rzeczy potrzebne w transakcji. Transakcje tak małe, jak to tylko możliwe, są zawsze dobre.

DatabaseContext db1 = new DatabaseContext(); 

doSomeDatabaseActions(db1); 

TransactionOptions transOpts = new TransactionOptions(); 
transOpts.IsolationLevel = System.Transactions.IsolationLevel.Serializable; 

using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, transOpts)) 
{ 
    using (DatabaseContext db2 = new DatabaseContext()) 
    { 
     doDatabaseChecksWithLock(db2); 
     doChanges(db2); 
     db2.SaveChanges(); 
    } 

    scope.Complete(); 
    } 

Mieliśmy problem bez wprowadzania drugiego połączenia.Zauważ, że błąd zniknął również przy użyciu 1 połączenia (db1), jeśli transakcja została powiększona (wprowadzono część transakcji doSomeDatabaseActions).

5

Zamiast pomocą funkcji śledzenia MSDTC (co znajdę strasznie spartański), mogę polecić za pomocą źródła śledzenia System.Transactions - wystarczy zaliczyć w Twojej web.config:
Jeśli otworzysz pliki dziennika z SvcTraceViewer.exe otrzymasz ładne wizualne przedstawienie kroków.

<configuration> 
    <system.diagnostics> 
    <trace autoflush="true" /> 
    <sources> 
    <source name="System.Transactions" switchValue="Information"> 
     <listeners> 
     <add name="tx" 
       type="System.Diagnostics.XmlWriterTraceListener" 
       initializeData="C:\MyApp-transactions-log.svclog" /> 
     </listeners> 
    </source> 
    </sources> 
    </system.diagnostics> 
</configuration> 

Nie jest to rozwiązanie samo w sobie, ale może to dostarczyć więcej informacji o tym, co jest nie tak.

+0

Świetny pomysł. Dokumenty wydają się być bardzo specyficzne dla WCF, ale zakładam, że nadal ma zastosowanie? –

+0

Nie sądzę, że jest to specyficzne dla WCF, System.Transactions jest zwykłym TraceSource. Format wyjściowy wygenerowany przez XmlWriterTraceListener wydaje się być taki sam, ale wiem, że nie trzeba go używać w połączeniu z aplikacją WCF. – Astrotrain

+0

Udało mi się użyć tej metody do rejestrowania momentu wystąpienia wyjątku, który faktycznie zatrzymuje dziennik martwy (znacznik środkowy). Zaktualizowałem pytanie, by uzyskać więcej informacji. –

1

Jak wspomniałeś "Aplikacja działa przez większość czasu, tylko sporadycznie wyświetla ten problem." przez to możemy wywnioskować, że dostawca obsługuje transakcje rozproszone, a przyczyną są inne, sporadyczne usterki związane z połączeniem lub obsługą.

  • używasz zagnieżdżone zakresy transakcji, bo jeśli z powodu jakiegoś powodu, zakres wewnętrzna jest cofnięty (unieszkodliwić bez wywoływania kompletne), które natychmiast wycofać transakcję zewnętrzną przyczyną błędu. Użyj opcji TransactionScopeOption.Required (funkcja RequNew również będzie działała, ale parametr RequiredNew zawiera inne problemy związane z zakleszczeniem, więc lepiej jest użyć parametru Required), aby rozwiązać ten problem:

  • W przeciwnym razie może to być spowodowane inną operacją, gdy transakcja jest aktywna i do rozwiązania w tym przypadku użyj IsolationLevel = IsolationLevel.ReadCommitted.

+1

Jeśli zadziałał, oznacz go jako poprawną/zaakceptowaną odpowiedź. – roopaliv

0

To może powinien być komentarz, ale jest za duży. Mam nadzieję, że to pomoże.

Jednym z najbardziej typowym błędem z transakcji zagnieżdżonych jest taka:

using(TransactionScope outerScope = new TransactionScope()) 
{ 
    // Execute query 1 

    using(TransactionScope innerScope = new TransactionScope()) 
    { 
     try 
     { 
      // Execute query 2 
     } 
     catch (Exception) 
     { 
     } 

     innerScope.Complete(); 
    } 

    outerScope.Complete(); 
} 

Teraz, jeśli kwerenda 2, która znajduje się wewnątrz bloku try/catch, rasies błąd można złapać wyjątek w try/catch zablokuj i obsłuż go, ale tutaj jest niespodzianka, że ​​aplikacja rzuci wyjątek ObjectDisposedException na linii 15 podczas próby ukończenia transakcji. Wynika to z faktu, że kod DTC już wychwycił wyjątek i mimo że go obsłużyłeś, obiekty TransactionScope, które zostały już usunięte przez kod .Net, a transakcja została wycofana. Zauważ, że powiedziałem "obiekty", ponieważ oba obiekty TransactionScope zostały usunięte, ponieważ są częścią tej samej transakcji.

+0

Jak mogę obsłużyć/zapobiec tej sytuacji? –