Wenn wir in unserer Anwendung auf Datenbankzugriff zugreifen müssen, verwenden wir die folgenden Muster:
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. work.Commit()
like so: 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:
Enlist=false
der Verbindungszeichenfolge meiner Anwendung hinzu, so dass sie sich nie in Ambient-Transaktionen einträgt. 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
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):
wobei CommitChanges
eine Transaktion akzeptiert - eventuell mit optionalen Parametern:
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.
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.
Tags und Links c# sql-server-2012 transactionscope msdtc rebus