Haben Sie ein Konstrukt wie
using (var scope = new TransactionScope(TransactionScopeOption.Required))
in C # gesehen? Dies bedeutet, dass sich der im
using
Block ausgeführte Code in der Transaktion befindet und nach dem Beenden dieses Blocks die Änderungen festgeschrieben oder zurückgesetzt werden. Es klingt verständlich, bis Sie anfangen, tiefer zu graben. Und je tiefer Sie graben, desto „seltsamer und seltsamer“ wird es. Als ich mich mit der
TransactionScope
Klasse und allgemein mit .NET-Transaktionen vertraut machte, stellten sich auf jeden Fall eine ganze Reihe von Fragen.
Was ist die
TransactionScope
Klasse? Sobald wir das Konstrukt
using (var scope = new TransactionScope())
verwenden, wird alles in unserem Programm sofort transaktional? Was sind "Ressourcenmanager" und "Transaktionsmanager"? Kann ich meinen eigenen Ressourcenmanager schreiben und wie wird eine Verbindung zur erstellten
TransactionScope
Instanz hergestellt? Was ist eine verteilte Transaktion und stimmt eine verteilte Transaktion in SQL Server oder Oracle Database mit einer verteilten .NET-Transaktion?
In dieser Veröffentlichung habe ich versucht, Material zu sammeln, das hilft, Antworten auf diese Fragen zu finden und ein Verständnis für Transaktionen in der .NET-Welt aufzubauen.
Einführung
Was sind Transaktionen und welche Probleme lösen sie?
Bei den hier in Rede stehenden Transaktionen handelt es sich um Vorgänge, die das System von einem akzeptablen Zustand in einen anderen übertragen und die das System garantiert nicht in einem inakzeptablen Zustand belassen, selbst wenn unvorhergesehene Situationen auftreten. Welche akzeptablen Bedingungen dies im Allgemeinen sind, hängt vom Kontext ab. Hier betrachten wir eine akzeptable Situation, in der die von uns verarbeiteten Daten ganzheitlich sind. Es versteht sich, dass die Änderungen, aus denen sich die Transaktion zusammensetzt, entweder zusammen oder nicht festgeschrieben werden. Darüber hinaus können Änderungen an einer Transaktion von Änderungen isoliert werden, die von einer anderen Transaktion am System vorgenommen wurden. Die Grundvoraussetzungen für Transaktionen werden mit dem Akronym ACID bezeichnet. Für die erste Bekanntschaft mit ihnen ist
ein Artikel auf Wikipedia geeignet.
Ein klassisches Beispiel für eine Transaktion ist der Geldtransfer zwischen zwei Konten. In dieser Situation ist das Abheben von Geld von Konto Nr. 1 ohne Gutschrift auf Konto Nr. 2 nicht akzeptabel, genau wie das Gutschreiben auf Konto Nr. 2 ohne Abheben von Konto Nr. 1. Mit anderen Worten, wir möchten, dass beide Vorgänge sowohl abheben als auch gutschreiben - sofort durchgeführt. Wenn einer von ihnen fehlschlägt, sollte der zweite Vorgang nicht ausgeführt werden. Sie können dieses Prinzip "alles oder nichts" nennen. Darüber hinaus ist es wünschenswert, dass Operationen auch bei Systemfehlern wie einem Stromausfall synchron ausgeführt werden, dh dass das System in einem akzeptablen Zustand ist, sobald es nach der Wiederherstellung verfügbar wird.
In mathematischen Begriffen können wir sagen, dass es in Bezug auf das System eine Invariante gibt, die wir beibehalten möchten. Zum Beispiel der Betrag auf beiden Konten: Es ist erforderlich, dass der Betrag nach der Transaktion (Geldtransfer) derselbe bleibt wie zuvor. Übrigens erscheint im klassischen Beispiel der Geldüberweisung auch die Buchhaltung - ein Themenbereich, in dem das Konzept der Transaktion natürlich entstanden ist.
Wir veranschaulichen das Beispiel des Geldtransfers zwischen zwei Konten. Das erste Bild zeigt die Situation, als die Übertragung von 50 Rubel von Konto Nr. 1 auf Konto Nr. 2 erfolgreich abgeschlossen wurde. Die grüne Farbe zeigt an, dass sich das System in einem akzeptablen Zustand befindet (Daten sind vollständig).
Stellen Sie sich nun vor, dass die Überweisung außerhalb der Transaktion erfolgt und nach dem Abheben von Geld von Konto Nr. 1 ein Fehler aufgetreten ist, aufgrund dessen das abgezogene Geld nicht auf Konto Nr. 2 gutgeschrieben wurde. Das System befindet sich in einem inakzeptablen Zustand (rote Farbe).
Wenn zwischen dem Auszahlungs- und dem Gutschriftvorgang ein Fehler aufgetreten ist, die Überweisung jedoch im Rahmen einer Transaktion durchgeführt wurde, wird der Auszahlungsvorgang abgebrochen. Infolgedessen bleibt das System in seinem ursprünglichen akzeptablen Zustand.
Ich werde Beispiele für Situationen aus der Erfahrung unseres Unternehmens nennen, in denen Transaktionen nützlich sind: Bilanzierung von Waren (Berücksichtigung der Anzahl von Waren verschiedener Arten, die sich in bestimmten Geschäften befinden und unterwegs sind), Bilanzierung von Lagerressourcen (Berücksichtigung des Volumens eines Raums, der von Waren eines bestimmten Typs belegt ist, Volumen eines Raums, frei für die Platzierung von Waren, die Menge an Waren, die Mitarbeiter und automatisierte Lagersysteme pro Tag bewegen können).
Die Probleme, die auftreten, wenn die Datenintegrität verletzt wird, liegen auf der Hand. Die vom System bereitgestellten Informationen werden nicht nur falsch - sie verlieren den Kontakt zur Realität und werden zu Unsinn.
Welche Transaktionen werden hier berücksichtigt?
Die Vorteile von Transaktionen sind bekannt. Benötigen wir zur Wahrung der Datenintegrität eine relationale Datenbank, da dort Transaktionen durchgeführt werden? Nicht wirklich. Es wurde oben gesagt, dass das Konzept einer Transaktion vom Kontext abhängt, und jetzt werden wir kurz überlegen, über welche Transaktionen wir bei der Diskussion von Informationssystemen sprechen können.
Zunächst trennen wir die Konzepte von Fachdomänentransaktionen (Geschäftstransaktionen) und Systemtransaktionen. Die zweite kann an verschiedenen Orten und auf verschiedene Arten implementiert werden.
Gehen wir von der höchsten Ebene - dem Themenbereich. Die interessierte Person kann erklären, dass es einige akzeptable Zustände gibt, und sie möchte das Informationssystem nicht außerhalb dieser Zustände sehen. Wir werden keine zusätzlichen Beispiele nennen: Hier ist die Überweisung von Geld zwischen Konten geeignet. Wir stellen nur klar, dass eine Überweisung nicht unbedingt eine Überweisung zwischen den Abrechnungskonten zweier Bankkunden ist. Nicht weniger wichtig ist die Aufgabe der Rechnungslegung, wenn die Konten die Quellen und den Zweck der Mittel der Organisation widerspiegeln sollten und die Übertragung die Änderung der Verteilung der Mittel nach diesen Quellen und Zwecken widerspiegeln sollte. Dies war ein Beispiel für eine
Betreff-Domain-Transaktion .
Lassen Sie uns nun die häufigsten und interessantesten Beispiele für die Implementierung von Systemtransaktionen sehen. Bei Systemtransaktionen stellen verschiedene technische Mittel die Anforderungen des Themenbereichs bereit. Eine klassisch bewährte Lösung dieser Art ist eine
relationale DBMS-Transaktion (erstes Beispiel). Moderne Datenbankverwaltungssysteme (sowohl relational
als auch nicht sehr ) bieten einen Transaktionsmechanismus, mit dem Sie entweder alle während des angegebenen Arbeitszeitraums vorgenommenen Änderungen speichern (festschreiben) oder verwerfen (Rollback) können. Bei Verwendung eines solchen Mechanismus werden Vorgänge zum Abheben von Geld von einem Konto und zur Gutschrift auf einem anderen Konto, aus denen die Transaktion des betreffenden Bereichs besteht, zu einer Systemtransaktion zusammengefasst und entweder zusammen oder überhaupt nicht ausgeführt.
Die Verwendung eines DBMS ist natürlich nicht erforderlich. Grob gesagt können Sie den DBMS-Transaktionsmechanismus im Allgemeinen in Ihrer bevorzugten Programmiersprache implementieren und das instabile und fehlerhafte Analogon vorhandener Tools genießen. Ihr „Fahrrad“ kann jedoch für bestimmte Situationen im Themenbereich optimiert werden.
Es gibt interessantere Optionen. Moderne industrielle Programmiersprachen (in erster Linie C # und Java) bieten Tools, die speziell für die Organisation von Transaktionen mit völlig unterschiedlichen Subsystemen und nicht nur für das DBMS entwickelt wurden. In dieser Veröffentlichung werden wir solche Transaktionssoftware nennen. Im Fall von C # sind dies
Transaktionen aus dem System.Transactions-Namespace (das zweite Beispiel), die im Folgenden beschrieben werden.
Bevor Sie zu
System.Transactions
Transaktionen
System.Transactions
, können Sie ein weiteres interessantes Phänomen erwähnen.
System.Transactions
Tools kann der Programmierer den
programmatischen Transaktionsspeicher unabhängig implementieren. In diesem Fall sind Programmoperationen, die sich auf den Status des Systems auswirken (bei klassischen imperativen Programmiersprachen handelt es sich um eine Zuweisungsoperation), standardmäßig in Transaktionen enthalten, die ähnlich wie DBMS-Transaktionen festgeschrieben und zurückgesetzt werden können. Mit diesem Ansatz wird die Notwendigkeit der Verwendung von Synchronisationsmechanismen (in C #
lock
, in Java-
synchronized
) erheblich reduziert. Eine Weiterentwicklung dieser Idee ist
der auf Plattformebene unterstützte Software-Transaktionsspeicher (drittes Beispiel). Ein solches Wunder wird voraussichtlich in einer Sprache zu finden sein, deren Eleganz die industrielle Anwendbarkeit übertrifft - Clojure. Und für Arbeiter-Bauern-Sprachen gibt es Plug-In-Bibliotheken, die die Funktionalität des programmatischen Transaktionsspeichers bereitstellen.
Systemtransaktionen können mehrere Informationssysteme umfassen. In diesem Fall werden sie verteilt. Verteilt können sowohl DBMS-Transaktionen als auch Software sein. Alles hängt davon ab, welche Funktionen ein bestimmtes Transaktionstool unterstützt. Detailliertere verteilte Transaktionen werden im entsprechenden Abschnitt erläutert. Ich werde ein Bild geben, um das Verständnis der besprochenen Themen zu erleichtern.
TL; DR-Abschnitt
Es gibt Prozesse, die aus mehreren unteilbaren (atomaren) Operationen bestehen, die auf das System angewendet werden, im allgemeinen Fall nicht unbedingt informativ. Jede unteilbare Operation kann das System in einem inakzeptablen Zustand belassen, wenn die Datenintegrität beeinträchtigt wird. Wenn beispielsweise eine Geldüberweisung zwischen zwei Konten durch zwei unteilbare Vorgänge dargestellt wird: Abheben vom Konto Nr. 1 und Gutschrift auf Konto Nr. 2, verletzt nur einer dieser Vorgänge die Integrität der Daten. Geld verschwindet entweder mitten im Nirgendwo oder erscheint mitten im Nirgendwo. Eine Transaktion kombiniert unteilbare Operationen, so dass sie alle zusammen (natürlich nacheinander, falls erforderlich) oder überhaupt nicht ausgeführt werden. Wir können über Domänentransaktionen und Transaktionen in technischen Systemen sprechen, die normalerweise Domänentransaktionen implementieren.
Transaktionen basierend auf System.Transactions
Was ist das
In der .NET-Welt gibt es ein Software-Framework, das von den Erstellern einer Transaktionsverwaltungsplattform entwickelt wurde. Aus Sicht eines Transaktionsprogrammierers besteht dieses Framework aus den
System.Transactions
TransactionScope
,
TransactionScopeOption
,
TransactionScopeAsyncFlowOption
und
TransactionOptions
System.Transactions
Namespace. Wenn wir über .NET Standard sprechen, ist all dies ab
Version 2.0 verfügbar.
Transaktionen aus dem
System.Transactions
Namespace basieren auf
dem X / Open XA-Standard von The Open Group . Dieser Standard führt viele der unten diskutierten Begriffe ein und beschreibt vor allem verteilte Transaktionen, die in dieser Veröffentlichung in einem speziellen Abschnitt ebenfalls behandelt werden. Die Implementierung von Softwaretransaktionen auf anderen Plattformen, beispielsweise
Java, basiert auf demselben Standard.
Ein typischer Transaktionsanwendungsfall für einen C # -Programmierer lautet wie folgt:
using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required)) {
Innerhalb des
using
Blocks befindet sich der Code, der die Arbeit erledigt, dessen Ergebnisse zusammen festgeschrieben oder abgebrochen werden müssen. Klassische Beispiele für solche Arbeiten sind das Lesen und Schreiben in die Datenbank oder das Senden und Empfangen von Nachrichten aus der Warteschlange. Wenn das Steuerelement den
using
Block verlässt, wird die Transaktion festgeschrieben. Wenn Sie den Anruf "
Complete
entfernen, wird die Transaktion zurückgesetzt. Ziemlich einfach.
Es stellt sich heraus, dass während eines Transaktions-Rollbacks alle Operationen, die in einem solchen
using
werden, abgebrochen werden. Und wenn ich einer Variablen einen anderen Wert zugewiesen habe, stellt diese Variable den alten Wert wieder her? Als ich zum ersten Mal ein ähnliches Design sah, dachte ich es mir. Tatsächlich werden natürlich nicht alle Änderungen rückgängig gemacht, sondern nur ganz
besondere . Wenn alle Änderungen überhaupt rückgängig gemacht würden, wäre dies der oben beschriebene Software-Transaktionsspeicher. Lassen Sie uns nun sehen, welche besonderen Änderungen an Programmtransaktionen auf der Basis von
System.Transactions
.
Ressourcenmanager
Damit Transaktionen auf der Basis von
System.Transactions
unterstützt werden
System.Transactions
, muss es über Informationen
System.Transactions
, dass eine Transaktion gerade ausgeführt wird, und dass sie in einer Registrierung von Transaktionsteilnehmern registriert ist. Sie können Informationen darüber
System.Transactions.Transaction
ob die Transaktionsarbeit ausgeführt wird, indem Sie die statische Eigenschaft
Current
der
System.Transactions.Transaction
Klasse
System.Transactions.Transaction
. Wenn Sie den
using
Block des oben angegebenen Typs eingeben, wird diese Eigenschaft nur festgelegt, wenn sie zuvor noch nicht festgelegt wurde.
Transaction.Enlist Smth
sich als Teilnehmer an einer Transaktion zu registrieren, können Sie Methoden vom Typ
Transaction.Enlist Smth
. Darüber hinaus müssen Sie die für diese Methoden erforderliche Schnittstelle implementieren. Ressourcenmanager - Dies ist ein solches „Etwas“, das die Interaktion mit Transaktionen von
System.Transactions
(eine genauere Definition finden Sie unten).
Was sind Ressourcenmanager? Wenn wir von C # aus mit einem DBMS arbeiten, z. B. SQL Server oder Oracle Database, verwenden wir normalerweise die entsprechenden Treiber und diese sind die Verwaltungsressourcen. Im Code werden sie durch die Typen
System.Data.SqlClient.SqlConnection
und
Oracle.ManagedDataAccess.Client.OracleConnection
.
Sie sagen auch, dass MSMQ Transaktionen unterstützt, die auf
System.Transactions
basieren. Anhand von Kenntnissen und Beispielen aus dem Internet können Sie Ihren eigenen Ressourcenmanager erstellen. Das einfachste Beispiel finden Sie im nächsten Abschnitt.
Zusätzlich zu den Ressourcenmanagern benötigen wir einen Transaktionsmanager, der die Transaktion überwacht und den Ressourcenmanagern rechtzeitig Befehle erteilt. Abhängig davon, welche Ressourcenmanager an der Transaktion beteiligt sind (welche Merkmale sie haben und wo sie sich befinden), sind verschiedene Transaktionsmanager mit der Arbeit verbunden. In diesem Fall erfolgt die Auswahl der entsprechenden Version automatisch und erfordert nicht die Intervention eines Programmierers.
System.Transactions.IEnlistmentNotification
ist der Ressourcenmanager eine Instanz einer Klasse, die die spezielle
System.Transactions.IEnlistmentNotification
Schnittstelle implementiert. Die vom Client
System.Transactions.Transaction.Current
mithilfe der statischen Eigenschaft
System.Transactions.Transaction.Current
als Teilnehmer an der Transaktion
System.Transactions.Transaction.Current
. Anschließend ruft der Transaktionsmanager nach Bedarf Methoden der angegebenen Schnittstelle auf.
Es ist klar, dass sich zur Laufzeit die Anzahl der an der Transaktion beteiligten Ressourcenmanager ändern kann. Nach Eingabe des
using
Blocks können wir beispielsweise zuerst etwas in SQL Server und dann in Oracle Database tun. Abhängig von dieser Gruppe von Ressourcenmanagern wird der verwendete Transaktionsmanager bestimmt. Genauer gesagt wird das verwendete Transaktionsprotokoll von der Gruppe der Ressourcenmanager bestimmt, und der Transaktionsmanager, der es unterstützt, wird basierend auf dem Protokoll bestimmt. Wir werden uns
später die Transaktionsprotokolle ansehen, wenn wir über verteilte Transaktionen sprechen. Der Mechanismus zum automatischen Auswählen des entsprechenden Transaktionsmanagers zur Laufzeit beim Ändern der an der Transaktion beteiligten Ressourcenmanager wird als Transaktionspromotion bezeichnet.
Arten von Ressourcenmanagern
Ressourcenmanager können in zwei große Gruppen unterteilt werden: dauerhaft und variabel.
Durable Resource Manager - Ein Ressourcenmanager, der eine Transaktion unterstützt, auch wenn das Informationssystem nicht verfügbar ist (z. B. beim Neustart des Computers). Volatile Resource Manager - Ein Ressourcenmanager, der eine Transaktion nicht unterstützt, wenn das Informationssystem nicht verfügbar ist. Ein inkonsistenter Ressourcenmanager unterstützt nur Transaktionen im Speicher.
Die klassischen langfristigen Ressourcenmanager sind das DBMS (oder der DBMS-Treiber für die Softwareplattform). Unabhängig davon, was passiert - zumindest eine Fehlfunktion des Betriebssystems, zumindest ein Stromausfall - garantiert das DBMS die Datenintegrität, nachdem es wieder in den Betriebszustand zurückgekehrt ist. Dafür müssen Sie natürlich einige Unannehmlichkeiten bezahlen, aber in diesem Artikel werden wir sie nicht berücksichtigen. Ein Beispiel für einen nicht persistenten Ressourcenmanager ist der oben erwähnte Software-Transaktionsspeicher.
Verwenden von TransactionScope
Beim Erstellen eines Objekts vom Typ
TransactionScope
Sie einige Parameter angeben.
Erstens gibt es eine Einstellung, die der Laufzeit mitteilt, was sie benötigt:
- Verwenden Sie eine Transaktion, die zu diesem Zeitpunkt bereits vorhanden ist.
- Stellen Sie sicher, dass Sie eine neue erstellen.
- Führen Sie umgekehrt Code innerhalb eines
using
Blocks außerhalb einer Transaktion aus.
Die
System.Transactions.TransactionScopeOption
Enumeration ist für all dies verantwortlich.
Zweitens können Sie die Transaktionsisolationsstufe festlegen. Dies ist ein Parameter, mit dem Sie einen Kompromiss zwischen der Unabhängigkeit von Änderung und Geschwindigkeit finden können. Die unabhängigste Ebene - serialisierbar - stellt sicher, dass es keine Situationen gibt, in denen Änderungen innerhalb einer Transaktion, die noch nicht festgeschrieben wurden, in einer anderen Transaktion sichtbar sind. Jede nächste Ebene fügt eine solche spezifische Situation hinzu, wenn sich gleichzeitig ausgeführte Transaktionen gegenseitig beeinflussen können.
Standardmäßig wird eine Transaktion auf serialisierbarer Ebene geöffnet, was unangenehm sein kann (siehe z. B. diesen Kommentar ).Das Festlegen der Transaktionsisolationsstufe während der Erstellung TransactionScope
ist für Ressourcenmanager ratsam. Sie unterstützen möglicherweise nicht einmal alle aufgelisteten Ebenen System.Transactions.IsolationLevel
. Darüber hinaus sollte berücksichtigt werden, dass bei Verwendung des Verbindungspools für die Arbeit mit der Datenbank die Verbindung, für die die Transaktionsisolationsstufe geändert wurde , diese Stufe bei der Rückkehr in den Pool beibehält . Wenn der Programmierer diese Verbindung aus dem Pool empfängt und sich auf die Standardwerte stützt, beobachtet er unerwartetes Verhalten.Typische Arbeitsszenarien cTransactionScope
und bedeutende Fallstricke (nämlich verschachtelte Transaktionen) werden in diesem Artikel über "Habr" ausführlich behandelt .Anwendbarkeit von Softwaretransaktionen
Es sollte gesagt werden, dass in fast jedem Informationssystem im kommerziellen Betrieb Prozesse gestartet werden, die das System in einen inakzeptablen Zustand führen können. Daher kann es erforderlich sein, diese Prozesse zu steuern, herauszufinden, ob der aktuelle Status des Systems akzeptabel ist, und ihn gegebenenfalls wiederherzustellen. Softwaretransaktionen - ein vorgefertigtes Tool, um das System in einem akzeptablen Zustand zu halten.In jedem Fall wäre es konstruktiv, die Kosten zu berücksichtigen:- Integration von Prozessen in die Software-Transaktionsinfrastruktur (diese Prozesse müssen sich auch
TransactionScope
vieler anderer Dinge bewusst sein ); - Wartung dieser Infrastruktur (z. B. die Kosten für die Anmietung von Geräten mit Windows an Bord);
- Mitarbeiterschulung (da das Thema .NET-Transaktionen nicht üblich ist).
Wir dürfen nicht vergessen, dass der Transaktionsprozess möglicherweise verpflichtet ist, seinen Fortschritt der "Außenwelt" zu melden, um beispielsweise ein Journal der Aktionen außerhalb der Transaktion zu führen.Offensichtlich erfordert die Ablehnung von Softwaretransaktionen die Schaffung oder Implementierung anderer Mittel zur Aufrechterhaltung der Datenintegrität, die ebenfalls ihren Wert haben werden. Letztendlich kann es Fälle geben, in denen Verstöße gegen die Datenintegrität so selten sind, dass es einfacher ist, durch chirurgische Eingriffe einen akzeptablen Zustand des Systems wiederherzustellen, als einen automatischen Wiederherstellungsmechanismus aufrechtzuerhalten.Ein Beispiel für einen unbeständigen Ressourcenmanager
Schauen wir uns nun ein Beispiel für einen einfachen Ressourcenmanager an, der die Wiederherstellung nach einem Systemfehler nicht unterstützt. Wir werden einen Block Software-Transaktionsspeicher haben, der einen Wert speichert, der gelesen und geschrieben werden kann. Wenn keine Transaktion vorhanden ist, verhält sich dieser Block wie eine reguläre Variable und speichert bei Vorhandensein einer Transaktion den Anfangswert, der nach dem Zurücksetzen der Transaktion wiederhergestellt werden kann. Der Code für einen solchen Ressourcenmanager ist unten dargestellt: internal sealed class Stm<T> : System.Transactions.IEnlistmentNotification { private T _current; private T _original; private bool _enlisted; public T Value { get { return _current; } set { if (!Enlist()) { _original = value; } _current = value; } } public Stm(T value) { _current = value; _original = value; } private bool Enlist() { if (_enlisted) return true; var currentTx = System.Transactions.Transaction.Current; if (currentTx == null) return false; currentTx.EnlistVolatile(this, System.Transactions.EnlistmentOptions.None); _enlisted = true; return true; } #region IEnlistmentNotification public void Commit(System.Transactions.Enlistment enlistment) { _original = _current; _enlisted = false; } public void InDoubt(System.Transactions.Enlistment enlistment) { _enlisted = false; } public void Prepare(System.Transactions.PreparingEnlistment preparingEnlistment) { preparingEnlistment.Prepared(); } public void Rollback(System.Transactions.Enlistment enlistment) { _current = _original; _enlisted = false; } #endregion IEnlistmentNotification }
Es ist ersichtlich, dass die einzige formale Anforderung die Implementierung der Schnittstelle ist System.Transactions.IEnlistmentNotification
. Von den interessanten Methoden Enlist
(die kein Teil sind System.Transactions.IEnlistmentNotification
) und Prepare
. Die Methode Enlist
prüft lediglich, ob der angegebene Code im Rahmen der Transaktion funktioniert, und registriert in diesem Fall eine Instanz ihrer Klasse als nicht konstanten Ressourcenmanager. Die Methode Prepare
wird vom Transaktionsmanager aufgerufen, bevor die Änderungen festgeschrieben werden. Unser Ressourcenmanager signalisiert seine Bereitschaft zum Festschreiben durch Aufrufen einer Methode System.Transactions.PreparingEnlistment.Prepared
.Der folgende Code zeigt ein Beispiel für die Verwendung unseres Ressourcenmanagers: var stm = new Stm<int>(1); using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required)) { stm.Value = 2; scope.Complete(); }
Wenn Sie using
die Eigenschaft unmittelbar nach dem Verlassen des Blocks lesen stm.Value
, wird dort der erwartete Wert erwartet 2
. Wenn Sie den Aufruf entfernen scope.Complete
, wird die Transaktion zurückgesetzt und für die Eigenschaft stm.Value
wird der Wert 1
vor dem Start der Transaktion festgelegt.Eine vereinfachte Abfolge von Aufrufen bei der Arbeit mit Transaktionen ist System.Transactions
in der folgenden Abbildung dargestellt.Es ist ersichtlich, dass in diesem Beispiel nicht alle von der Infrastruktur bereitgestellten Möglichkeiten berücksichtigt werden System.Transactions
. Wir werden sie im nächsten Abschnitt genauer betrachten, nachdem wir uns mit Transaktionsprotokollen und verteilten Transaktionen vertraut gemacht haben.TL; DR-Abschnitt
Ein Programmierer kann eine Klasse verwenden TransactionScope
, um Code innerhalb einer vorhandenen oder neuen Transaktion auszuführen. Eine Transaktion wird genau dann festgeschrieben, wenn die TransactionScope
Methode für eine vorhandene Instanz der Klasse Dispose
aufgerufen wird, obwohl die Methode zuvor aufgerufen wurdeComplete
. Ein Programmierer kann angeben, ob er eine neue Transaktion starten, eine vorhandene nutzen oder umgekehrt Code außerhalb einer vorhandenen Transaktion ausführen möchte. An der Transaktion sind nur Ressourcenmanager beteiligt - Softwarekomponenten, die bestimmte Funktionen implementieren. Ressourcenmanager können langfristig (Wiederherstellung nach einem Systemfehler) und zeitweise (nicht Wiederherstellung) sein. Ein DBMS ist ein Beispiel für einen langlebigen Ressourcenmanager. Der Ressourcenmanager wird von einem Transaktionsmanager koordiniert - einer Softwarekomponente, die von der Laufzeit ohne Teilnahme eines Programmierers automatisch ausgewählt wird.Inkonsistenter Ressourcenmanager ist eine Klasse, die die Schnittstelle System.Transactions.IEnlistmentNotification
in der Methode implementiertPrepare
Bestätigung der Bereitschaft, Änderungen festzuschreiben, oder umgekehrt Signalisierung eines Rollbacks von Änderungen. Wenn der Aufrufer etwas mit dem Ressourcenmanager tut, prüft er, ob die Transaktion jetzt geöffnet ist, und meldet sich mit der Methode an, wenn sie geöffnet ist System.Transactions.Transaction.EnlistVolatile
.Verteilte Transaktionen
Was ist das
Eine verteilte Transaktion umfasst mehrere Informationssubsysteme (tatsächlich ist nicht alles so einfach, mehr dazu weiter unten). Es versteht sich, dass Änderungen in allen Systemen, die an einer verteilten Transaktion beteiligt sind, entweder festgeschrieben oder zurückgesetzt werden müssen.Oben wurden verschiedene Mittel zur Implementierung von Transaktionen vorgestellt: DBMS, Infrastruktur System.Transactions
und programmatischer Transaktionsspeicher, die in die Plattform integriert sind. Mit diesen Tools können auch verteilte Transaktionen bereitgestellt werden. Wenn Sie beispielsweise in der Oracle-Datenbank Daten in mehreren Datenbanken innerhalb einer einzelnen Transaktion ändern (und tatsächlich lesen), werden diese automatisch in verteilte Daten umgewandelt. Als nächstes werden wir über Software-verteilte Transaktionen sprechen, zu denen auch heterogene Ressourcenmanager gehören können.Transaktionsprotokolle
Ein Transaktionsprotokoll ist eine Reihe von Prinzipien, nach denen die an einer Transaktion beteiligten Anwendungen interagieren. In der .NET-Welt werden die folgenden Protokolle am häufigsten verwendet.Leicht. Es wird nicht mehr als ein dauerhafter Ressourcenmanager verwendet. Alle Transaktionsinteraktionen finden innerhalb derselben Anwendungsdomäne statt, oder der Ressourcenmanager unterstützt die Heraufstufung und das einphasige Festschreiben (Implementieren IPromotableSinglePhaseNotification
).OleTx. Die Interoperabilität zwischen mehreren Anwendungsdomänen und mehreren Computern ist zulässig. Sie können viele dauerhafte Ressourcenmanager verwenden. Auf allen teilnehmenden Computern muss Windows ausgeführt werden. Verwenden Sie Remote Procedure Calls (RPCs).WS-AT.Die Interoperabilität zwischen mehreren Anwendungsdomänen und mehreren Computern ist zulässig. Sie können viele dauerhafte Ressourcenmanager verwenden. Auf den teilnehmenden Computern werden möglicherweise verschiedene Betriebssysteme ausgeführt, nicht nur Windows. Das Hypertext Transmission Protocol (HTTP) wird verwendet.Es wurde oben angemerkt, dass das aktuelle Transaktionsprotokoll die Wahl des Transaktionsmanagers beeinflusst und die Eigenschaften der an der Transaktion beteiligten Kontrollressourcen die Wahl des Protokolls beeinflussen. Jetzt listen wir die bekannten Transaktionsmanager auf.Lightweight Transaction Manager (LTM) . Eingeführt in .NET Framework 2.0 und höher. Verwaltet Transaktionen mithilfe des Lightweight-Protokolls.Kernel Transaction Manager (KTM). Eingeführt in Windows Vista und Windows Server 2008. Verwaltet Transaktionen mithilfe des Lightweight-Protokolls. Es kann ein Transaktionsdateisystem (TxF) und eine Transaktionsregistrierung (TxR) unter Windows Vista und Windows 2008aufrufen . Distributed Transaction Coordinator (MSDTC) . Verwaltet Transaktionen mit den Protokollen OleTx und WS-AT.Es sollte auch berücksichtigt werden, dass einige Ressourcenmanager nicht alle aufgeführten Protokolle unterstützen. Beispielsweise unterstützen MSMQ und SQL Server 2000 Lightweight nicht, sodass Transaktionen mit MSMQ oder SQL Server 2000 von MSDTC verwaltet werden, selbst wenn sie die einzigen Teilnehmer sind. Technisch ergibt sich diese Einschränkung aus der Tatsache, dass die angegebenen Ressourcenmanager natürlich die Schnittstelle implementierenSystem.Transactions.IEnlistmentNotification
Implementieren Sie die Schnittstelle nicht System.Transactions.IPromotableSinglePhaseNotification
. Es enthält unter anderem eine Methode Promote
, die die Laufzeit bei Bedarf aufruft, um zu einem steileren Transaktionsmanager zu wechseln.Die Mehrdeutigkeit des Konzepts der verteilten Transaktion sollte nun offensichtlich werden. Beispielsweise können Sie eine verteilte Transaktion als eine Transaktion definieren, an der sie teilnimmt:- mindestens zwei Ressourcenmanager;
- willkürlich variable Ressourcenmanager und mindestens zwei langlebige;
- Mindestens zwei Ressourcenmanager befinden sich notwendigerweise auf verschiedenen Computern.
Daher ist es besser, immer zu klären, um welche Transaktionen es sich handelt.In diesem Zusammenhang wird vor allem MSDTC diskutiert. Es ist eine Softwarekomponente von Windows, die verteilte Transaktionen verwaltet. Es gibt eine grafische Oberfläche zum Konfigurieren und Überwachen von Transaktionen, die Sie im Dienstprogramm "Komponentendienste" unter dem Pfad "Computer - Arbeitsplatz - Koordinator für verteilte Transaktionen - Lokaler DTC" finden.Wählen Sie zur Konfiguration im Kontextmenü des Knotens „Lokaler DTC“ das Element „Eigenschaften“ aus. Um verteilte Transaktionen zu überwachen, wählen Sie im zentralen Bereich das Element „Transaktionsstatistik“ aus.Zweiphasige Fixierung
Wenn mehrere Ressourcenmanager an der Transaktion teilnehmen, können die Ergebnisse ihrer Arbeit unterschiedlich sein: Beispielsweise wurde einer von ihnen erfolgreich abgeschlossen, und er ist bereit, die Änderungen festzuschreiben, und der andere hat einen Fehler, und er wird die Änderungen rückgängig machen. Das Wesentliche einer verteilten Transaktion liegt jedoch in der Tatsache, dass Änderungen an allen an der Transaktion beteiligten Steuerungsressourcen entweder alle zusammen festgeschrieben oder zurückgesetzt werden. Daher wird in solchen Fällen üblicherweise ein zweiphasiges Fixierungsprotokoll verwendet.Im Allgemeinen ist das Wesentliche dieses Protokolls wie folgt. Während der ersten PhaseAn der Transaktion beteiligte Ressourcenmanager bereiten Informationen vor, die ausreichen, um den Fehler zu beheben (wenn es sich um einen langfristigen Ressourcenmanager handelt) und um als Ergebnis eines Commits erfolgreich abgeschlossen zu werden. Aus technischer Sicht signalisiert der Ressourcenmanager, dass er die erste Phase abgeschlossen hat, indem er die Methode System.Transactions.PreparingEnlistment.Prepared
in der Methode aufruft Prepare
. Oder der Ressourcenmanager kann Sie durch Aufrufen der Methode benachrichtigen, dass die Änderungen rückgängig gemacht wurden ForceRollback
.Wenn alle an der Transaktion beteiligten Ressourcenmanager „abgestimmt“ haben, dh dem Transaktionsmanager mitgeteilt haben, ob sie die Änderungen festschreiben oder zurücksetzen möchten, beginnt die zweite Phase. Zu diesem Zeitpunkt werden Ressourcenmanager angewiesen, ihre Änderungen festzuschreiben (wenn alle Teilnehmer für die Korrektur gestimmt haben) oder Änderungen abzulehnen (wenn mindestens ein Teilnehmer für das Rollback gestimmt hat). Technisch wird dies als Methodenaufrufe ausgedrückt Commit
und Rollback
die Ressourcenmanager implementieren, und in dem sie verursachen ein Verfahren System.Transactions.Enlistment.Done
.Der Ressourcenmanager kann die Methode auch System.Transactions.Enlistment.Done
in der ersten Phase aufrufen . In diesem Fall wird davon ausgegangen, dass er keine Änderungen vornehmen wird (z. B. nur zum Lesen) und nicht an der zweiten Phase teilnehmen wird. Lesen Sie mehr über das Zwei-Phasen-Commit bei Microsoft .Wenn die Verbindung zwischen dem Transaktionsmanager und mindestens einem der Ressourcenmanager unterbrochen wird, wird die Transaktion eingefroren ("im Zweifel", im Zweifel). Der Transaktionsmanager InDoubt
benachrichtigt durch Aufrufen von Methoden verfügbare Ressourcenmanager über dieses Ereignis, die angemessen reagieren können.Es gibt immer noch eine dreiphasige Fixierung und ihre Modifikationen mit ihren Vor- und Nachteilen. Das dreiphasige Festschreibungsprotokoll ist weniger verbreitet, möglicherweise weil es noch mehr Kommunikationskosten zwischen den interagierenden Subsystemen erfordert.Spickzettel auf System.Transactions-Schnittstellen
Etwas ist schwierig. Um die Dinge ein wenig zu klären, werde ich kurz die wichtigsten Namespace-Schnittstellen beschreiben, die System.Transactions
zum Erstellen eines Ressourcenmanagers erforderlich sind. Hier ist ein Klassendiagramm.IEnlistmentNotification. Der Ressourcenmanager implementiert diese Schnittstelle. Der Transaktionsmanager ruft die implementierten Methoden in der folgenden Reihenfolge auf. In der ersten Phase ruft er die Methode auf Prepare
(es sei denn, die Sterne kamen zusammen, um die Methode aufzurufen ISinglePhaseNotification.SinglePhaseCommit
, wie im nächsten Absatz beschrieben). Bei dieser Methode speichert der Ressourcenmanager die Informationen, die zur Wiederherstellung nach einem Fehler erforderlich sind, bereitet die endgültige Festschreibung von Änderungen auf seiner Seite vor und stimmt ab, die Änderungen festzuschreiben oder zurückzusetzen. Wenn es eine zweite Phase kommt, in Abhängigkeit von der Verfügbarkeit von Ressourcen und die Kontrolle über die Abstimmungsergebnisse der Steuer Transaktion ist ein von drei Methoden: Commit
, InDoubt
, Rollback
.ISinglePhaseNotification.Der Ressourcenmanager implementiert diese Schnittstelle, wenn er dem Transaktionsmanager die Möglichkeit geben möchte, die Ausführung zu optimieren, indem er die zweite Festschreibungsphase reduziert. Wenn der Transaktionsmanager nur einen Ressourcenmanager sieht, versucht er in der ersten Festschreibungsphase SinglePhaseCommit
(stattdessen IEnlistmentNotification.Prepare
), die Methode des Ressourcenmanagers aufzurufen und damit die Abstimmung und den Übergang zur zweiten Phase auszuschließen. Dieser Ansatz hat Vor- und Nachteile, über die Microsoft hier am deutlichsten geschrieben hat .ITransactionPromoter. Der Ressourcenmanager implementiert diese Schnittstelle (nicht nur direkt, sondern über die SchnittstelleIPromotableSinglePhaseNotification
), wenn er dem Transaktionsmanager die Möglichkeit geben möchte, das Lightweight-Protokoll auch bei Fernaufrufen einzuhalten, bis andere Bedingungen auftreten, die eine Protokollkomplikation erfordern. Wenn Sie das Protokoll komplizieren müssen, wird die Methode aufgerufen Promote
.IPromotableSinglePhaseNotification. Der Ressourcenmanager implementiert diese Schnittstelle, um zum einen die Schnittstelle zu implementieren ITransactionPromoter
und zum anderen, damit der Transaktionsmanager einphasiges Festschreiben, Aufrufen von Methoden IPromotableSinglePhaseNotification.SinglePhaseCommit
und verwenden kann IPromotableSinglePhaseNotification.Rollback
. Der Transaktionsmanager ruft eine Methode IPromotableSinglePhaseNotification.Initialize
auf, um die erfolgreiche Registrierung des Ressourcenmanagers auf vereinfachte Weise zu markieren. Mehr oder weniger kann dies aus einem Microsoft-Dokument verstanden werden .Schauen wir uns etwas mehr anSystem.Transactions.Enlistment
und seine Erben. Dieser Instanztyp wird vom Transaktionsmanager bereitgestellt, wenn er die vom Ressourcenmanager implementierten Schnittstellenmethoden aufruft.Einberufung. Der Ressourcenmanager kann eine einzelne Methode dieses Typs - Done
, - aufrufen , um den erfolgreichen Abschluss seines Teils der Arbeit zu signalisieren.Vorbereitung der Eintragung. Mit einer Instanz dieses Typs während der ersten Festschreibungsphase kann der Ressourcenmanager seine Absicht signalisieren, die Änderungen festzuschreiben oder zurückzusetzen. Ein langlebiger Ressourcenmanager kann auch die Informationen abrufen, die zur Wiederherstellung nach einem Systemfehler erforderlich sind.SinglePhaseEnlistment. Mit einer Instanz dieses Typs kann der Ressourcenmanager dem Transaktionsmanager mithilfe eines vereinfachten Schemas (einphasiges Festschreiben) Informationen über die Ergebnisse seiner Arbeit übermitteln.Einschränkungen und Alternativen für verteilte Software-Transaktionen
Eine kurze Untersuchung der im Internet gefundenen Meinungen zeigt, dass verteilte Transaktionen in vielen Bereichen aus der Mode kommen. Schauen Sie sich zum Beispiel diesen böswilligen Kommentar an . Das Hauptziel der Kritik, die kurz erwähnt hier - synchron (Blockierung) ist die Art von verteilten Transaktionen. Wenn ein Benutzer eine Anforderung sendet, während deren Verarbeitung eine verteilte Transaktion organisiert wurde, erhält er eine Antwort erst, nachdem (erfolgreich oder fehlerhaft) alle in der Transaktion enthaltenen Subsysteme die Arbeit beendet haben. Gleichzeitig gibt es eine von der Forschung gestützte Meinung, dass das Zwei-Phasen-Festschreibungsprotokoll eine schlechte Leistung aufweist, insbesondere mit einer Zunahme der Anzahl der an der Transaktion beteiligten Subsysteme, wie beispielsweise in erwähntdiese Veröffentlichung auf "Habré" .Wenn der Ersteller des Systems es vorzieht, die Antwort so schnell wie möglich an den Benutzer zurückzusenden und die Datenkoordination auf einen späteren Zeitpunkt zu verschieben, ist eine andere Lösung für ihn besser geeignet. Im Kontext des Brewer-Theorems ( CAP-Theorem ) können wir sagen, dass verteilte Transaktionen für Fälle geeignet sind, in denen Datenkonsistenz wichtiger ist als Verfügbarkeit.Es gibt andere praktische Einschränkungen für die Verwendung von Software-verteilten Transaktionen. Beispielsweise wurde experimentell festgestellt, dass verteilte Transaktionen, die das OleTx-Protokoll verwenden, keine Netzwerkdomänen überschreiten sollten. Auf jeden Fall waren lange Versuche, sie zur Arbeit zu bringen, nicht erfolgreich. Darüber hinaus wurde festgestellt, dass die Interaktion zwischen mehreren Instanzen von Oracle Database (verteilte Datenbanktransaktionen) die Anwendbarkeit von verteilten Software-Transaktionen erheblich einschränkt (erneut fehlgeschlagen).Was sind die Alternativen zu verteilten Transaktionen? Zunächst muss ich sagen, dass es sehr schwierig sein wird, auf technische Transaktionen (normal, nicht verteilt) zu verzichten. Es gibt wahrscheinlich Prozesse im System, die die Datenintegrität vorübergehend stören können, und es wird notwendig sein, diese Prozesse irgendwie zu überwachen. Ebenso kann sich in Bezug auf den Themenbereich ein Konzept ergeben, das einen Prozess umfasst, der durch eine Reihe von Prozessen in verschiedenen technischen Systemen implementiert wird und im Bereich integraler Daten beginnen und enden sollte.Wenn wir zu Alternativen zu verteilten Transaktionen übergehen, können wir Lösungen feststellen, die auf Messaging-Diensten wie RabbitMQ und Apache Kafka basieren. In dieser Veröffentlichung zu "Habré" werden vier solcher Lösungen betrachtet:- , , ;
- , (Transaction Log Tailing);
- , ;
- (Event Sourcing).
Eine weitere Alternative ist die Saga-Vorlage. Es handelt sich um eine Kaskade von Subsystemen mit ihren lokalen Transaktionen. Nach Abschluss der Arbeiten ruft jedes System Folgendes auf (entweder unabhängig oder mit Hilfe eines Koordinators). Für jede Transaktion gibt es eine entsprechende Stornierungstransaktion, und anstatt die Kontrolle zu übertragen, kann das Subsystem die Stornierung von Änderungen initiieren, die zuvor von den vorherigen Subsystemen vorgenommen wurden. Auf "Habré" gibt es einige gute Artikel über die Vorlage "Saga". Zum Beispiel in dieser Veröffentlichung ist die allgemeine Information über die ACID Prinzipien sind in mikrosluzhbah beibehalten, und in diesem Artikel beschreibt die Fallstudie Vorlage „Saga“ mit dem Koordinator.In unserem Unternehmen verwenden einige Produkte erfolgreich Software-verteilte Transaktionen über WCF, es gibt jedoch auch andere Optionen. Als wir einmal versuchten, Freunde mit verteilten Transaktionen zu einem neuen System zu machen, hatten wir viele Probleme, einschließlich einer Kollision mit den oben beschriebenen Einschränkungen und parallelen Problemen bei der Aktualisierung der Software-Infrastruktur. Daher haben wir unter Bedingungen eines Mangels an Ressourcen für die Durchführung einer anderen Kapitalentscheidung die folgenden Taktiken angewendet. Der angerufene Teilnehmer erfasst die Änderungen in jedem Fall, stellt jedoch fest, dass sie sich in einem Entwurfszustand befinden, sodass diese Änderungen den Betrieb des angerufenen Systems noch nicht beeinträchtigen. Wenn der Anrufer dann seine Arbeit über eine verteilte Transaktion abschließt, aktiviert das DBMS die vom aufgerufenen System vorgenommenen Änderungen. Auf diese Weise,Anstelle von Software-verteilten Transaktionen verwendeten wir verteilte DBMS-Transaktionen, die sich in diesem Fall als viel zuverlässiger herausstellten.Also ist es in .NET Core?
In .NET Core (und sogar in .NET Standard) gibt es alle erforderlichen Typen zum Organisieren von Transaktionen und zum Erstellen eines eigenen Ressourcenmanagers. Leider System.Transactions
haben basierende Transaktionen in .NET Core eine schwerwiegende Einschränkung: Sie funktionieren nur mit dem Lightweight-Protokoll. Wenn beispielsweise zwei dauerhafte Ressourcenmanager im Code verwendet werden, löst die Umgebung zur Laufzeit eine Ausnahme aus, sobald der zweite Manager aufgerufen wird.Tatsache ist, dass sie versuchen, .NET Core vom Betriebssystem unabhängig zu machen, sodass die Verknüpfung zu Transaktionsmanagern wie KTM und MSDTC ausgeschlossen ist, dh sie werden zur Unterstützung von Transaktionen mit den angegebenen Eigenschaften benötigt. Es ist möglich, dass die Verbindung von Transaktionsmanagern in Form von Plug-Ins implementiert wird. Bisher wurde dies jedoch mit einer Heugabel geschrieben, sodass Sie sich noch nicht auf die industrielle Verwendung verteilter Transaktionen in .NET Core verlassen können.Erfahrungsgemäß können Sie die Unterschiede bei verteilten Transaktionen in .NET Framework und in .NET Core überprüfen, indem Sie denselben Code schreiben, ihn kompilieren und auf verschiedenen Plattformen ausführen.Ein Beispiel für einen solchen Code, der SQL Server und Oracle Database nacheinander aufruft. private static void Main(string[] args) { using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required)) { MsSqlServer(); Oracle(); scope.Complete(); } } private static void Oracle() { using (var conn = new Oracle.ManagedDataAccess.Client.OracleConnection("User Id=some_user;Password=some_password;Data Source=some_db")) { conn.Open(); using (var cmd = conn.CreateCommand()) { cmd.CommandText = "update t_hello set id_hello = 2 where id_hello = 1"; cmd.ExecuteNonQuery(); } conn.Close(); } } private static void MsSqlServer() { var builder = new System.Data.SqlClient.SqlConnectionStringBuilder { DataSource = "some_computer\\some_db", UserID = "some_user", Password = "some_password", InitialCatalog = "some_scheme", Enlist = true, }; using (var conn = new System.Data.SqlClient.SqlConnection(builder.ConnectionString)) { conn.Open(); using (var cmd = conn.CreateCommand()) { cmd.CommandText = "update t_hello set id_hello = 2 where id_hello = 1"; cmd.ExecuteNonQuery(); } conn.Close(); } }
Build-Ready-Projekte sind auf GitHub .Das Ausführen des Beispiels für .NET Core schlägt fehl. Der Ort und der Typ der ausgelösten Ausnahme hängen von der Reihenfolge des DBMS-Aufrufs ab. In jedem Fall weist diese Ausnahme jedoch auf eine ungültige Transaktionsoperation hin. Das Ausführen des Beispiels für .NET Framework ist erfolgreich, wenn MSDTC zu diesem Zeitpunkt ausgeführt wird. In der grafischen Oberfläche von MSDTC können Sie jedoch die Registrierung einer verteilten Transaktion beobachten.Verteilte Transaktionen und WCF
Die Windows Communication Foundation (WCF) ist das .NET-Framework zum Organisieren und Aufrufen von Netzwerkdiensten. Im Vergleich zu den modischeren REST- und ASP.NET-Web-API-Ansätzen hat es seine eigenen Vor- und Nachteile. WCF ist mit .NET-Transaktionen sehr gut befreundet, und in der Welt von .NET Framework ist es praktisch, es zum Organisieren von Transaktionen zu verwenden, die zwischen dem Client und dem Dienst verteilt werden.In .NET Core funktioniert diese Technologie nur auf der Clientseite. Das heißt, Sie können keinen Dienst erstellen, sondern nur auf einen vorhandenen Dienst verweisen. Dies ist jedoch nicht sehr wichtig, da, wie oben erwähnt, bei verteilten Transaktionen in .NET Core die Dinge überhaupt nicht gut laufen.Wie WCF funktioniertFür Leser, die mit WCF nicht vertraut sind, finden Sie hier die kürzesten Hintergrundinformationen zur Praxis dieser Technologie. Kontext - zwei Informationssysteme, die als Client und Service bezeichnet werden. Der Client greift zur Laufzeit auf ein anderes Informationssystem zu, das den für den Client interessanten Dienst unterstützt, und erfordert, dass eine Operation ausgeführt wird. Anschließend wird die Verwaltung an den Client zurückgegeben.Um einen Dienst in WCF zu erstellen, müssen Sie normalerweise eine Schnittstelle schreiben, die den Vertrag für den zu erstellenden Dienst beschreibt, und eine Klasse, die diese Schnittstelle implementiert. Die Klasse und die Schnittstelle sind mit speziellen WCF-Attributen gekennzeichnet, die sie von den übrigen Typen unterscheiden und einige Details des Verhaltens während der Ermittlung und des Aufrufs des Dienstes angeben. Diese Typen sind in einen Server eingebunden (z. B. in eine DLL, für die IIS festgelegt ist) und werden durch eine Konfigurationsdatei (es gibt Optionen) ergänzt, in der Details zur Dienstimplementierung angegeben sind. Nach dem Start kann auf den Dienst beispielsweise unter der Netzwerkadresse zugegriffen werden. Im Internetbrowser sehen Sie die Verträge, die der angeforderte Dienst implementiert.Ein Programmierer, der auf einen vorhandenen WCF-Dienst zugreifen möchte, verwendet ein in die Entwicklungsumgebung integriertes Konsolendienstprogramm oder eine grafische Oberfläche, um Typen in C # (oder einer anderen unterstützten Sprache) zu bilden, die Serviceverträgen an der Adresse des Dienstes entsprechen. Die Datei mit den erhaltenen Typen ist im Clientanwendungsprojekt enthalten. Danach verwendet der Programmierer dieselben Begriffe, die in der Serviceschnittstelle enthalten sind, und nutzt die Vorteile des Fortschritts (statische Typisierung). Darüber hinaus gibt die Konfigurationsdatei des Clients die technischen Merkmale des aufgerufenen Dienstes an (sie kann auch ohne Konfigurationsdatei im Code konfiguriert werden).WCF unterstützt verschiedene Arten von Transport, Verschlüsselung und anderen subtileren technischen Parametern. Die meisten von ihnen sind durch das Konzept der "Bindung" (Bindung) verbunden. Der WCF-Dienst verfügt über drei wichtige Parameter:- die Adresse, unter der es verfügbar ist;
- Bindung
- Vertrag (Schnittstellen).
Alle diese Parameter werden in den Service- und Client-Konfigurationsdateien festgelegt.In unserem Unternehmen wird WCF (mit und ohne verteilte Transaktionen) häufig in implementierten Produkten verwendet. Angesichts der Modetrends ist die Verwendung in neuen Produkten jedoch immer noch fraglich.So initiieren Sie verteilte Transaktionen in WCFUm initiierte Transaktionen in WCF zu initiieren System.Transactions
, muss der Programmierer mehrere Attribute im Code festlegen, sicherstellen, dass die verwendeten Bindungen verteilte Transaktionen unterstützen, transactionFlow="true"
dass sie auf dem Client und im Service geschrieben sind und dass der entsprechende Transaktionsmanager auf allen beteiligten Computern ausgeführt wird (höchstwahrscheinlich) wird es MSDTC sein).Verteilte Transaktionsbindungen: NetTcpBinding, NetNamedPipeBinding, WSHttpBinding, WSDualHttpBinding und WSFederationHttpBinding.Die Methode (Operation) der Serviceschnittstelle muss mit einem Attribut gekennzeichnet sein System.ServiceModel.TransactionFlowAttribute
. Bei bestimmten Attributparametern und beim Festlegen des TransactionScopeRequired
Attributparameters wird die System.ServiceModel.OperationBehaviorAttribute
Transaktion dann zwischen dem Client und dem Dienst verteilt. Darüber hinaus wird standardmäßig davon ausgegangen, dass der Dienst für das Festschreiben der Transaktion abstimmt, es sei denn, zur Laufzeit wird eine Ausnahme ausgelöst. Um dieses Verhalten zu ändern, müssen Sie den entsprechenden TransactionAutoComplete
Attributparameterwert festlegen System.ServiceModel.OperationBehaviorAttribute
.Der Code für einen einfachen WCF-Dienst, der verteilte Transaktionen unterstützt. [System.ServiceModel.ServiceContract] public interface IMyService { [System.ServiceModel.OperationContract] [System.ServiceModel.TransactionFlow(System.ServiceModel.TransactionFlowOption.Mandatory)] int DoSomething(string input); } public class MyService : IMyService { [System.ServiceModel.OperationBehavior(TransactionScopeRequired = true)] [System.ServiceModel.TransactionFlow(System.ServiceModel.TransactionFlowOption.Mandatory)] public int DoSomething(string input) { if (input == null) throw new System.ArgumentNullException(nameof(input)); return input.Length; } }
Offensichtlich unterscheidet es sich vom regulären Servicecode nur in der Verwendung des Attributs System.ServiceModel.TransactionFlow
und in der speziellen Einstellung des Attributs System.ServiceModel.OperationBehavior
. Beispielkonfiguration für diesen Dienst. <system.serviceModel> <services> <service name="WcfWithTransactionsExample.MyService" behaviorConfiguration="serviceBehavior"> <endpoint address="" binding="wsHttpBinding" bindingConfiguration="mainWsBinding" contract="WcfWithTransactionsExample.IMyService"/> <endpoint address="mex" contract="IMetadataExchange" binding="mexHttpBinding"/> </service> </services> <bindings> <wsHttpBinding> <binding name="mainWsBinding" maxReceivedMessageSize="209715200" maxBufferPoolSize="209715200" transactionFlow="true" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"> <security mode="None"/> <readerQuotas maxArrayLength="209715200" maxStringContentLength="209715200"/> </binding> </wsHttpBinding> </bindings> </system.serviceModel>
Beachten Sie, dass die Bindung vom Typ WSHttpBinding ist und das Attribut verwendet wird transactionFlow="true"
. TL; DR-Abschnitt
Verteilte Transaktionen umfassen mehrere Ressourcenmanager, und alle Änderungen müssen entweder festgeschrieben oder zurückgesetzt werden. Einige moderne DBMS implementieren verteilte Transaktionen, die einen bequemen Mechanismus zum Verbinden mehrerer Datenbanken bieten. Verteilte Transaktionen mit Software (nicht in DBMS implementiert) können verschiedene Kombinationen von Ressourcenmanagern auf verschiedenen Computern enthalten, auf denen verschiedene Betriebssysteme ausgeführt werden. Sie weisen jedoch Einschränkungen auf, die berücksichtigt werden müssen, bevor Sie sich auf sie verlassen können. Eine moderne Alternative zu verteilten Transaktionen sind Messaging-Lösungen. In .NET Core werden verteilte Transaktionen noch nicht unterstützt.WCF ist eines der standardmäßigen und bewährten Tools zum Erstellen und Zugreifen auf Dienste in der .NET-Welt und unterstützt verschiedene Arten von Transport und Verschlüsselung. WCF ist sehr eng mit verteilten Transaktionen befreundet System.Transactions
. Das Einrichten verteilter Transaktionen für WCF besteht darin, den Code mit mehreren Attributen zu markieren und den Dienst- und Clientkonfigurationsdateien einige Wörter hinzuzufügen. Nicht alle WCF-Bindungen unterstützen verteilte Transaktionen. Darüber hinaus ist klar, dass Transaktionen in WCF dieselben Einschränkungen aufweisen wie ohne Verwendung von WCF. Mit der .NET Core-Plattform können Sie bisher nur auf Dienste in WCF zugreifen, anstatt sie zu erstellen.Fazit Krippe
Dieser Beitrag bietet einen Überblick über die Grundlagen von .NET-Softwaretransaktionen. Einige Schlussfolgerungen zu Trends bei Softwaretransaktionen finden Sie in den Abschnitten zur Anwendbarkeit und zu den Einschränkungen der behandelten Themen. Abschließend werden die wichtigsten Thesen der Veröffentlichung zusammengefasst. Ich nehme an, dass sie als Spickzettel verwendet werden können, wenn Softwaretransaktionen als eine der Optionen zur Implementierung eines technischen Systems oder zum Aktualisieren relevanter Informationen im Speicher betrachtet werden.Transaktionen (Themenbereich, DBMS, Software). Domänenanforderungen werden manchmal in Form von Transaktionen formuliert - Operationen, die, beginnend im Bereich integraler Daten, nach Abschluss (einschließlich erfolglos) auch in den Bereich integraler Daten (möglicherweise bereits anders) fallen sollten. Diese Anforderungen werden normalerweise als Systemtransaktionen implementiert. Ein klassisches Beispiel für eine Transaktion ist die Überweisung von Geld zwischen zwei Konten, die aus zwei unteilbaren Vorgängen besteht: Abheben von Geld von einem Konto und Gutschrift auf einem anderen. Neben den bekannten Transaktionen, die vom DBMS implementiert werden, gibt es auch Softwaretransaktionen, beispielsweise in der .NET-Welt. Ressourcenmanager sind Softwarekomponenten, die sich der Existenz solcher Transaktionen bewusst sind und in diese einbezogen werden können, dh vorgenommene Änderungen festschreiben oder zurücksetzen.Ressourcenmanager erhalten vom Transaktionsmanager, der die Grundlage der Infrastruktur bildet, Anweisungen zum Festschreiben und Zurücksetzen von ÄnderungenSystem.Transactions
.Langlebige und zeitweise Ressourcenmanager. Langfristige Ressourcenmanager unterstützen die Datenwiederherstellung nach einem Systemausfall. DBMS-Treiber für .NET bieten normalerweise solche Funktionen. Intermittierende Ressourcenmanager unterstützen keine Notfallwiederherstellung. Der programmatische Transaktionsspeicher - eine Möglichkeit zur Verwaltung von Objekten im RAM - kann als Beispiel für einen unbeständigen Ressourcenmanager angesehen werden.Transaktionen und .NET-Ressourcenmanager. Der .NET-Programmierer verwendet Softwaretransaktionen und erstellt seine eigenen Ressourcenmanager mithilfe von Typen aus dem NamespaceSystem.Transactions
. Diese Infrastruktur ermöglicht die Verwendung von Transaktionen mit verschiedenen Verschachtelungen und Isolationen (mit bekannten Einschränkungen). Die Verwendung von Transaktionen ist nicht kompliziert und besteht darin, den Code in einen Block using
mit bestimmten Merkmalen zu verpacken . Die auf diese Weise in die Transaktion einbezogenen Ressourcenmanager müssen jedoch die erforderlichen Funktionen für ihren Teil beibehalten. Die Verwendung heterogener Ressourcenmanager in einer Transaktion oder die Verwendung eines Managers auf unterschiedliche Weise kann eine Transaktion automatisch in eine verteilte verwandeln.Verteilte Transaktionen (DBMS, Software).Eine verteilte Transaktion umfasst mehrere Subsysteme, deren Änderungen synchronisiert werden müssen, dh sie werden entweder alle zusammen festgeschrieben oder zurückgesetzt. Verteilte Transaktionen sind in einigen modernen DBMS implementiert. Durch Software verteilte Transaktionen (dies sind nicht diejenigen, die vom DBMS implementiert werden) unterliegen zusätzlichen Einschränkungen für die interagierenden Prozesse und Plattformen. Verteilte Transaktionen geraten nach und nach aus der Mode und weichen Lösungen, die auf Messaging-Diensten basieren. Um eine normale Transaktion in eine verteilte zu verwandeln, muss der Programmierer nichts tun: Wenn zur Laufzeit ein Ressourcenmanager mit bestimmten Merkmalen in der Transaktion enthalten ist, führt der Transaktionsmanager automatisch alles aus, was erforderlich ist. Regelmäßige Softwaretransaktionen sind in .NET Core und .NET Standard verfügbar, verteilte Transaktionen sind nicht verfügbar.Verteilte Transaktionen über WCF. WCF ist eines der Standard-.NET-Tools zum Erstellen und Aufrufen von Diensten, das auch standardisierte Protokolle unterstützt. Mit anderen Worten, auf WCF-Dienste, die auf eine bestimmte Weise konfiguriert sind, kann von jeder Anwendung aus zugegriffen werden, nicht nur von .NET oder Windows. Um eine verteilte Transaktion über WCF zu erstellen, müssen Sie die Typen, aus denen der Dienst besteht, mit zusätzlichen Attributen kennzeichnen und minimale Änderungen an den Dienst- und Clientkonfigurationsdateien vornehmen. Sie können keine WCF-Dienste in .NET Core und .NET Standard erstellen, aber Sie können WCF-Clients erstellen.Beispiel für die Überprüfung von System.Transactions auf GitHub