SqlConnection und Vermeidung der Beförderung zu MSDTC

9

Wenn wir in unserer Anwendung auf Datenbankzugriff zugreifen müssen, verwenden wir die folgenden Muster:

  • Für die Abfrage haben wir eine statische Factory-Klasse mit einer Methode CreateOpenConnection , die nicht mehr als new SqlConnection(myConnectionString) ausführt und Open() darauf aufruft. Diese Methode wird aufgerufen, bevor eine Abfrage ausgeführt wird, und die Verbindung wird nach der Abfrage zurückgegeben.
  • Für Einfügungen / Aktualisierungen / Löschungen verwenden wir ein Unit of Work-Muster, in dem die Änderungen zusammengefasst und mit einem Aufruf von work.Commit() like so:
  • an die Datenbank gesendet werden

work.Commit:

%Vor%

Dies scheint für den allgemeinen Gebrauch als Teil eines Webservice gut zu funktionieren, gibt mir jedoch MSDTC Ärger, wenn ich versuche, dies in Kombination mit Rebus zu verwenden.

Von dem, was ich sagen kann, erstellt Rebus (wenn es eine Nachricht in der Warteschlange behandelt) ein neues TransactionScope , so dass im Falle eines Fehlers, die Nachricht zu verarbeiten, ein Rollback durchgeführt werden kann. Nun, das hat an sich schon gut funktioniert. Ich kann ein neues SqlConnection in einem Rebus-Meldungshandler ohne irgendwelche Probleme öffnen (aber unsere alten Entity Framework-Abfragen zu verwenden und manuelle SqlConnections innerhalb der gleichen Rebus TransactionScope funktioniert nicht, aber ich don Ich halte das jetzt für ein Problem. Aber gestern habe ich folgende Frage gestellt:

Serielle Verarbeitung eines bestimmten Nachrichtentyps in Rebus

Auf die Antwort scheint die Verwendung der Saga-Funktion von Rebus zu sein. Ich habe versucht, dies zu implementieren und es so konfiguriert, dass die Rebus-Saga in einer neuen SQL Server-Datenbank (mit einer eindeutigen Verbindungszeichenfolge) beibehalten wird. Vermutlich wird durch die Verwendung dieser Persistenz von SQL Server ein eigenes SqlConnection geöffnet, da ich jedes Mal, wenn ich versuche, SqlConnection zu erstellen, die folgende Ausnahme erhalte:

  

Der Netzwerkzugriff für Distributed Transaction Manager (MSDTC) wurde deaktiviert. Aktivieren Sie DTC für den Netzwerkzugriff in der Sicherheitskonfiguration für MSDTC mithilfe des Verwaltungstools für Komponentendienste.

Die Aktivierung von MSDTC würde ich sehr, sehr sehr in Bezug auf Konfigurations- und Leistungsaufwand vermeiden wollen. Und ich mag mich irren, aber es scheint auch nicht notwendig.

Was ich hier vermute, ist, dass Rebus ein Ambient TransactionScope erstellt und dass das SqlConnection , das es erstellt, sich in diesem Bereich einträgt. Und wenn ich versuche, mein eigenes SqlConnection zu erstellen, versucht es auch, sich auf diesen Ambient-Bereich zu beziehen, und da mehrere Verbindungen beteiligt sind, wird es zu MSDTC hochgestuft, was fehlschlägt.

Ich habe eine Idee, wie ich das beheben kann, aber ich weiß nicht, ob es richtig ist. Was ich tun würde, ist:

  • Fügen Sie Enlist=false der Verbindungszeichenfolge meiner Anwendung hinzu, so dass sie sich nie in Ambient-Transaktionen einträgt.
  • Ändere die Commit -Methode so, dass sie kein neues TransactionScope erzeugt (was meine Verbindung nicht mehr abonnieren wird, weil ich gerade gesagt habe, dass das nicht funktionieren sollte), aber dass conn.BeginTransaction verwendet wird.

Wie so:

%Vor%

Ich bin mir nur nicht sicher, ob das der richtige Ansatz ist und welche möglichen Nachteile es gibt.

Irgendwelche Tipps?

UPDATE: Zur Klarstellung, es ist nicht die work.Commit() , die mir Probleme bereitet hat, ich bin mir ziemlich sicher, dass es funktionieren würde, aber ich komme nie dorthin, weil meine Abfrage was scheitert.

Ein Beispiel dafür, was fehlschlägt:

%Vor%

Dies wird aufgerufen, wenn ein TransactionScope von Rebus erstellt wurde, sowie nachdem ein SqlConnection von Rebus geöffnet wurde. Nach dem Öffnen von mein SqlConnection , versucht es zu registrieren und stürzt ab

    
JulianR 31.05.2013, 09:50
quelle

2 Antworten

3

Ich bin etwas überrascht, dass Sie das sehen, weil RequiresNew sollte bedeutet, dass es von der anderen Transaktion isoliert ist; Normalerweise bedeutet diese Nachricht, dass 2 Verbindungen innerhalb eines Transaktionsbereichs aktiviert wurden - sind Sie sicher gibt es keinen anderen Code, der eine Verbindung innerhalb dieses Blocks erstellt / öffnet?

Ihre vorgeschlagene Lösung sollte funktionieren - obwohl TransactionScopeOption.Suppress in mancher Hinsicht bequemer sein kann als das Ändern Ihrer Konfiguration (aber beide sollten funktionieren). Allerdings gibt es ein Problem: ADO.NET-Transaktionen müssen an die einzelnen Befehle übergeben werden, so dass Sie benötigen (auch den Code ein wenig aufräumen):

%Vor%

wobei CommitChanges eine Transaktion akzeptiert - eventuell mit optionalen Parametern:

%Vor%

Ihre Benennung von DapperFactory legt nahe, dass Sie "dapper" verwenden - in diesem Fall können Sie das einfach an "dapper" übergeben, egal ob es null ist oder nicht, d. h.

%Vor%     
Marc Gravell 31.05.2013, 10:13
quelle
1

Dies hängt hauptsächlich von der Version von SQL Server ab, die Sie verwenden. Siehe hier für eine SO-Frage zu einem ähnlichen Problem.

Es geht darum, wie sich SQL 2005 und SQL 2008 bei der Verarbeitung mehrerer Verbindungen innerhalb derselben TransactionScope unterscheiden. d. h. SQL 2008 kann mehrere Verbindungen in der gleichen TransactionScope öffnen, ohne an die MSDTC zu eskalieren.

Könnte dies das Problem sein, das Sie sehen?

Wenn das der Fall ist, denke ich, dass die einzigen zwei Optionen das Upgrade auf SQL 2008 sind oder das MSDTC aktivieren. Ich verstehe, dass diese beiden Optionen wahrscheinlich massive Kopfschmerzen sind.

    
jaywayco 31.05.2013 10:11
quelle