TransactionScope eskaliert auf einigen Computern automatisch zu MSDTC?

In unserem Projekt verwenden wir TransactionScope, um sicherzustellen, dass unsere Datenzugriffsebene ihre Aktionen in einer Transaktion ausführt. Wir zielen darauf abnicht erfordern, dass der MSDTC-Dienst auf den Computern unserer Endbenutzer aktiviert ist.

Das Problem ist, dass wir auf der Hälfte unserer Entwicklermaschinen MSDTC deaktiviert haben. Die andere Hälfte muss es aktiviert haben, sonst bekommen sie das"MSDTC auf [SERVER] ist nicht verfügbar" Fehlermeldung.

Es hat mich wirklich dazu gebracht, mir den Kopf zu kratzen, und ich habe ernsthaft darüber nachgedacht, auf eine hausgemachte TransactionScope-ähnliche Lösung zurückzugreifen, die auf ADO.NET-Transaktionsobjekten basiert. Es scheint verrückt zu sein - derselbe Code, der für die Hälfte der Entwickler funktioniert (und nicht eskaliert)tut eskalieren auf dem anderen Entwickler.

Ich hatte auf eine bessere Antwort gehofftVerfolgen Sie, warum eine Transaktion zu DTC eskaliert wird aber leider nicht.

Hier ist ein Beispielcode, der das Problem verursacht: Auf den Computern, die versuchen zu eskalieren, wird versucht, es bei der zweiten Verbindung zu eskalieren. Open () (und ja, es ist zurzeit keine andere Verbindung geöffnet.)

using (TransactionScope transactionScope = new TransactionScope() {
   using (SqlConnection connection = new SqlConnection(_ConStr)) {
      using (SqlCommand command = connection.CreateCommand()) {
         // prep the command
         connection.Open();
         using (SqlDataReader reader = command.ExecuteReader()) {
            // use the reader
            connection.Close();
         }
      }
   }

   // Do other stuff here that may or may not involve enlisting 
   // in the ambient transaction

   using (SqlConnection connection = new SqlConnection(_ConStr)) {
      using (SqlCommand command = connection.CreateCommand()) {
         // prep the command
         connection.Open();  // Throws "MSDTC on [SERVER] is unavailable" on some...

         // gets here on only half of the developer machines.
      }
      connection.Close();
   }

   transactionScope.Complete();
}

Wir haben uns wirklich eingegraben und versucht, das herauszufinden. Hier sind einige Informationen zu den Maschinen, auf denen es funktioniert:

Entwickler 1: Windows 7 x64 SQL2008Entwickler 2: Windows 7 x86 SQL2008Entwickler 3: Windows 7 x64SQL2005 SQL2008

Entwickler, auf denen es nicht funktioniert:

Entwickler 4: Windows 7 x64,SQL2008 SQL2005Entwickler 5: Windows Vista x86, SQL2005Entwickler 6: Windows XP X86, SQL2005Mein Heim-PC: Windows Vista Home Premium, x86, SQL2005

Ich sollte hinzufügen, dass alle Computer, um dem Problem auf die Spur zu kommen, vollständig mit allem gepatcht wurden, was von Microsoft Update verfügbar ist.

Update 1:http://social.msdn.microsoft.com/forums/en-US/windowstransactionsprogramming/thread/a5462509-8d6d-4828-aefa-a197456081d3/ beschreibt ein ähnliches Problem ... im Jahr 2006!http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope%28VS.80%29.aspx - Wenn Sie dieses Codebeispiel lesen, wird eine sekundengenaue Verbindung (tatsächlich zu einem zweiten SQL-Server) deutlich, die zu DTC eskaliert.Wir machen das nicht in unserem Code - Wir verwenden weder unterschiedliche SQL-Server, noch unterschiedliche Verbindungszeichenfolgen, noch haben wir geschachtelte sekundäre Verbindungen geöffnet. -Es sollte keine Eskalation zu DTC geben.http://davidhayden.com/blog/dave/archive/2005/12/09/2615.aspx (ab 2005) spricht darüber, wie eine Eskalation zu DTC immer stattfinden wird, wenn eine Verbindung zu SQL2000 hergestellt wird. Wir verwenden SQL2005 / 2008http://msdn.microsoft.com/en-us/library/ms229978.aspx MSDN bei Transaktionseskalation.

Auf dieser Seite zur Eskalation von MSDN-Transaktionen wird angegeben, dass eine Transaktion unter den folgenden Bedingungen auf DTC eskaliert:

In der Transaktion ist mindestens eine dauerhafte Ressource eingetragen, die keine einphasigen Benachrichtigungen unterstützt.Mindestens zwei dauerhafte Ressourcen, die einphasige Benachrichtigungen unterstützen, werden in die Transaktion aufgenommen. Wenn Sie beispielsweise eine einzelne Verbindung mit registrieren, wird keine Transaktion heraufgestuft. Wenn Sie jedoch eine zweite Verbindung zu einer Datenbank herstellen, die die Registrierung der Datenbank verursacht, erkennt die System.Transactions-Infrastruktur, dass es sich um die zweite dauerhafte Ressource in der Transaktion handelt, und eskaliert sie zu einer MSDTC-Transaktion.Eine Anforderung zum "Marshallen" der Transaktion auf eine andere Anwendungsdomäne oder einen anderen Prozess wird aufgerufen. Zum Beispiel die Serialisierung des Transaktionsobjekts über eine Anwendungsdomänengrenze hinweg. Das Transaktionsobjekt wird nach Wert gemarshallt, was bedeutet, dass jeder Versuch, es über eine Anwendungsdomänengrenze (auch im selben Prozess) zu übergeben, zur Serialisierung des Transaktionsobjekts führt. Sie können die Transaktionsobjekte übergeben, indem Sie eine Remotemethode aufrufen, die eine Transaktion als Parameter verwendet, oder Sie können versuchen, auf eine Komponente mit Remotetransaktionsservice zuzugreifen. Dies serialisiert das Transaktionsobjekt und führt zu einer Eskalation, wie wenn eine Transaktion über eine Anwendungsdomäne serialisiert wird. Es wird verteilt und der lokale Transaktionsmanager ist nicht mehr ausreichend.

Wir erleben nicht # 3. Nr. 2 findet nicht statt, da immer nur eine Verbindung besteht und es sich auch um eine einzige "dauerhafte Ressource" handelt. Gibt es eine Möglichkeit, dass # 1 passieren könnte? Einige SQL2005 / 8-Konfigurationen, die dazu führen, dass einphasige Benachrichtigungen nicht unterstützt werden?

Update 2:

Alle SQL Server-Versionen wurden persönlich überprüft - "Dev 3" hat tatsächlich SQL2008, und "Dev 4" ist tatsächlich SQL2005. Das wird mich lehren, meinen Mitarbeitern nie wieder zu vertrauen. ;) Aufgrund dieser Datenänderung bin ich mir ziemlich sicher, dass wir unser Problem gefunden haben. Unsere SQL2008-Entwickler hatten das Problem nicht, da in SQL2008 eine Fülle von fantastischen Inhalten enthalten ist, die in SQL2005 nicht vorhanden sind.

Da wir SQL2005 unterstützen, können wir TransactionScope nicht wie bisher verwenden. Wenn wir TransactionScope verwenden möchten, müssen wir ein einzelnes SqlConnection-Objekt übergeben ... Dies scheint problematisch in Situationen zu sein, in denen SqlConnection nicht einfach weitergegeben werden kann. Es riecht nur nach einer globalen SqlConnection-Instanz. Bank!

Update 3

Nur um hier in der Frage zu klären:

SQL2008:

Ermöglicht mehrere Verbindungen innerhalb eines einzelnen TransactionScope (wie im obigen Beispielcode gezeigt).Vorsichtsmaßnahme Nr. 1: Wenn diese mehreren SqlConnections verschachtelt sind, dh wenn zwei oder mehr SqlConnections gleichzeitig geöffnet sind, wird TransactionScope sofort zu DTC eskalieren.Vorsichtsmaßnahme 2: Wenn eine zusätzliche SqlConnection für eine andere geöffnet wird"dauerhafte Ressource" (dh: ein anderer SQL Server), es wird sofort zu DTC eskaliert

SQL2005:

Ermöglicht nicht mehrere Verbindungen innerhalb eines einzigen TransactionScope-Zeitraums. Es wird eskalieren, wenn / wenn eine zweite SqlConnection geöffnet wird.Update 4

Im Interesse, diese Frage noch mehr zu stellenein Chaos Nützlich und nur aus Gründen der Übersichtlichkeit können Sie SQL2005 so einrichten, dass es mit a zu DTC eskaliertSingle SqlConnection:

using (TransactionScope transactionScope = new TransactionScope()) {
   using (SqlConnection connection = new SqlConnection(connectionString)) {
      connection.Open();
      connection.Close();
      connection.Open(); // escalates to DTC
   }
}

Das scheint mir nur kaputt zu sein, aber ich glaube ich kann verstehen, wenn jeder anruftSqlConnection.Open() greift nach dem Verbindungspool.

"Warum könnte das aber passieren?" Wenn Sie vor dem Öffnen einen SqlTableAdapter für diese Verbindung verwenden, öffnet und schließt der SqlTableAdapter die Verbindung und beendet die Transaktion für Sie, da Sie sie jetzt nicht wieder öffnen können.

Um TransactionScope mit SQL2005 erfolgreich zu verwenden, müssen Sie also eine Art globales Verbindungsobjekt haben, das ab dem Zeitpunkt geöffnet bleibt, an dem das erste TransactionScope instanziiert wird, bis es nicht mehr benötigt wird. Neben dem Code-Geruch eines globalen Verbindungsobjekts steht das Öffnen der Verbindung als erstes und das Schließen der Verbindung als letztes im Widerspruch zu der Logik, eine Verbindung so spät wie möglich zu öffnen und sie so bald wie möglich zu schließen.

Antworten auf die Frage(6)

Ihre Antwort auf die Frage