Eine kurze Analyse, wie MySQL die Transaktionsisolierung implementiert

Eine kurze Analyse, wie MySQL die Transaktionsisolierung implementiert

1. Einleitung

Wie wir alle wissen, kann beim Abfragen von Daten auf der RR-Isolationsebene von MySQL sichergestellt werden, dass die Daten nicht von anderen Transaktionen beeinflusst werden. Auf der RC-Isolationsebene werden jedoch die Daten nach dem Commit gelesen, solange andere Transaktionen festgeschrieben sind. Was ist also das Prinzip der Transaktionsisolation? Wie wird das erreicht? Dies muss über den MVCC-Mechanismus ( Multi-Version Concurrency Control ) erfolgen.

Hinweis: Der Grund, warum die InnoDB-Engine von MySQL Hochleistungs-Parallelität unterstützen kann, liegt am MVCC-Mechanismus von MySQL (dank Undo-Log, Read-View usw.), dieser Artikel stellt MVCC jedoch nicht im Detail vor.

Referenz: Reihe „MySQL Practice 45 Lectures“. Obwohl die Erklärung relativ klar ist, erfordert sie dennoch Verständnis. Ich denke beispielsweise, dass der Teil über Ansichtsarrays nicht klar erklärt ist, daher zeichne ich ihn in Kombination mit den Materialien und meinen eigenen Erkenntnissen auf!

2. RC- und RR-Isolationsstufen

Wir öffnen die Isolationsebenen RC und RR. Nehmen wir zunächst an, dass es eine Kontotabelle gibt. Vor dem Start der Transaktion ABC beträgt der Kontostand 1, d. h.

wähle Kontostand von Konto =1; # Das Ergebnis ist 1

2.1. Abfrageergebnisse unter RR-Transaktionsisolationsebene

Wenn drei Transaktionen auf der RR-Transaktionsisolationsebene geöffnet werden, werden die folgenden Vorgänge in unterschiedlichen Zeiträumen ausgeführt

  • Transaktion A (Transaktion explizit öffnen und manuell bestätigen): Saldo abfragen
  • Transaktion B (Transaktion explizit starten, manuell committen): 1 zum Saldo von id=1 hinzufügen
  • Transaktion C (Transaktion nicht explizit gestartet, automatisch festgeschrieben): 1 zum Saldo von id=1 hinzufügen

Wir unterteilen die Zeit logisch in drei Phasen und analysieren die Ergebnisse.

  • Phase 1: Transaktion A startet die Transaktion sofort, gefolgt von Transaktion B, und dann aktualisiert Transaktion C den Saldo erfolgreich auf 2. Der aktuelle Saldo = 2.
  • Phase 2: Transaktion B aktualisiert den Saldowert. Zu diesem Zeitpunkt liest sie zuerst den aktuellen Saldowert als 2, setzt dann erfolgreich Saldo = Saldo + 1 und den aktuellen Saldo = 3;
  • Phase 3: Transaktion A fragt den Wert des Kontostands ab, der jetzt 1 beträgt (warum ist er gleich 1? Wie wird er erreicht? Sollte er nicht der aktuelle letzte Wert von 3 sein? Dies ist der Schwerpunkt dieses Blogbeitrags). Schließlich beendet Commit die Transaktion, und dann führt auch Transaktion B ein Commit aus, um die Transaktion zu beenden.

Schließlich ist das Ergebnis des Lesesaldos von Transaktion A 1. Natürlich steht RR für wiederholbares Lesen, d. h. die Daten, die während der Ausführung einer Transaktion angezeigt werden, stimmen immer mit den Daten überein, die beim Start der Transaktion angezeigt werden. Ob die aktuelle Transaktion festgeschrieben wird oder nicht, hat keine Auswirkungen auf die Daten. Ich muss nur Daten basierend auf dem Snapshot lesen, also Snapshot-Lesen. Wir möchten jedoch diskutieren, wie dies im Rahmen des MVCC-Mechanismus implementiert werden kann.

Hinweis: Der Befehl begin/start transaction ist nicht der Startpunkt einer Transaktion. Die Transaktion wird tatsächlich gestartet, nachdem die erste Anweisung ausgeführt wurde, die die InnoDB-Tabelle bedient. Wenn Sie eine Transaktion sofort starten möchten, können Sie den Befehl „Transaktion mit konsistentem Snapshot starten“ verwenden.

2.2. Abfrageergebnisse unter RC-Transaktionsisolationsebene

In ähnlicher Weise starten wir die Transaktion ABC unter RC-Isolation und beobachten das endgültige Saldenergebnis der Transaktion A.

Schließlich ist das Ergebnis des von Transaktion A gelesenen Saldos 2. Natürlich steht RC für „Read Committable“, was wörtlich bedeutet, dass ich, solange andere Transaktionen festgeschrieben sind, sofort den neuesten aktuellen Wert der aktuellen Transaktion lesen kann. Dies ist der aktuelle Lesevorgang. Wir möchten jedoch diskutieren, wie dies im Rahmen des MVCC-Mechanismus implementiert werden kann.

Tatsächlich liegt dies daran, dass die bei der Implementierung von MVCC verwendete konsistente Lese-Ansicht zur Unterstützung der Implementierung der Isolationsebenen RC (Read Committed) und RR (Repeatable Read) verwendet wird.

3. Implementierung der Transaktionsisolierung in MVCC

Bevor wir besprechen, wie MVCC die Transaktionsisolierung erreicht, müssen wir Konzepte wie Ansichtsarrays und konsistente Ansichten kennen, um besser zu verstehen, wie MVCC zur Isolierung von Transaktionen beiträgt.

3.1. Mehrere Versionen von Datenzeilen ROW

Jede Transaktion in InnoDB hat eine eindeutige Transaktions-ID, die sogenannte Transaktions-ID. Es wird zu Beginn der Transaktion auf das InnoDB-Transaktionssystem angewendet und streng in der Reihenfolge der Anwendung erhöht.

Jede Datenzeile hat auch mehrere Versionen. Jedes Mal, wenn eine Transaktion Daten aktualisiert, wird eine neue Datenversion generiert und die Transaktions-ID dieser Datenversion wird der Transaktions-ID zugewiesen, die als Zeile „trx_id“ aufgezeichnet wird. Gleichzeitig muss die alte Datenversion beibehalten werden und in der neuen Datenversion sollten Informationen vorhanden sein, um diese direkt abzurufen (zu finden über die Datei undo_log).

Das heißt, eine Datensatzzeile in einer Datentabelle kann tatsächlich mehrere Versionen (Zeilen) haben und jede Version hat ihre eigene Zeilen-trx_id.

Zeichnen Sie die folgende Abbildung, um Ihr Verständnis des Multiversionskontrollprozesses einer Datenzeile ROW zu vertiefen, die zu einem bestimmten Zeitpunkt drei Aktualisierungstransaktionen durchläuft.

Aus der Abbildung können wir Folgendes ableiten:

  • ROW hat vier Versionen V1-V4. Nach drei Aktualisierungen des Kontostands ist die neueste Version V4. Der aktuelle Kontostand wurde auf 4 aktualisiert, was dem neuesten Wert entspricht.
  • InnoDB weist der Zeile trx_id die von jeder Aktualisierungstransaktion generierte Transaktions-ID zu.
  • Über undo_log können Sie von V4 auf V1 zurücksetzen und feststellen, dass der Saldo von V1 1 ist, was der Rollback-Version von undo_log entspricht.

Das Verständnis des Multiversionsprinzips und der Implementierung von Datenzeilen ROW kann uns helfen zu verstehen, wie InnoDB Snapshots definiert und erstellt!

3.2 Array anzeigen

Die folgenden Teile stammen aus den Originalsätzen in den Materialien. Insbesondere die rot markierten Teile können schwer zu verstehen sein, daher müssen Sie Ihr eigenes Verständnis kombinieren und Bilder zeichnen.

So definiert InnoDB Snapshots, wenn eine Transaktion gestartet wird. Welche Transaktionsoperationen kann ich ignorieren und welche müssen im Snapshot gespeichert werden? Es kann wie folgt verstanden werden: Eine Transaktion muss beim Start nur deklarieren: „Basierend auf dem Zeitpunkt meines Starts werde ich sie erkennen, wenn eine Datenversion vor meinem Start generiert wird. Wenn sie nach meinem Start generiert wird, werde ich sie nicht erkennen und muss ihre vorherige Version finden.“

In Bezug auf die Implementierung erstellt InnoDB für jede Transaktion ein Array, um alle Transaktions-IDs zu speichern, die zum Zeitpunkt des Starts der Transaktion aktuell „aktiv“ sind. „Aktiv“ bedeutet, dass es gestartet, aber noch nicht übermittelt wurde. Der Mindestwert der Transaktions-ID im Array wird als Untergrenze aufgezeichnet, und der Höchstwert der Transaktions-ID, die im aktuellen System erstellt wurde, plus 1 wird als Obergrenze aufgezeichnet. Dieses Ansichtsarray und die Hochwassermarke bilden die konsistente Ansicht (Lese-Ansicht) der aktuellen Transaktion.

Mein Verständnis von Niedrigwasserstand und Hochwasserstand:

Niedrigste Marke = der minimale ID-Wert aller aktuell gestarteten, aber noch nicht festgeschriebenen Transaktionssätze = der minimale ID-Wert der letzten vor der aktuellen Transaktion gestarteten, aber noch nicht festgeschriebenen Transaktion (der minimale ID-Wert aller aktiven Transaktionen)

High Water Mark = aktuelle Transaktions-ID (aktuelle ROW-Versionsnummer/Zeile trx_id) = Maximalwert der erstellten Transaktions-ID + 1

Beispiel: Nehmen Sie immer noch die drei ABC-Transaktionen unter der obigen RR-Isolationsstufe als Beispiel

  • Bevor Transaktion A startet, gibt es im System nur eine aktive Transaktion mit der ID 99;
  • Die Versionsnummern der Transaktionen A, B und C sind 100, 101 und 102, und im aktuellen System gibt es nur diese vier Transaktionen.
  • Vor dem Start der drei Transaktionen betrug die Zeile trx_id der Datenreihe (id,balance)=(1,1) den Wert 90.

Somit ist das Ansichtsarray der Transaktion A [99], das Ansichtsarray der Transaktion B ist [99,100] und das Ansichtsarray der Transaktion C ist [99,100,101]. Das heißt, die allgemeine Formel für das Ansichtsarray lautet: [{eine Sammlung aktiver Transaktions-IDs zum Zeitpunkt des Öffnens der aktuellen Transaktion}].

Die Sichtbarkeitsregeln der Datenversionen basieren auf den Vergleichsergebnissen von rowtrx_id und der Konsistenzansicht, daher müssen wir auch die Konsistenzansicht verstehen.

3.3. Konsistenzansicht

Durch das Verständnis des Ansichtsarrays wird die konsistente Ansicht einfacher, d. h. dieses Ansichtsarray und die Hochwassermarke bilden die konsistente Ansicht (Lese-Ansicht) der aktuellen Transaktion.

Nehmen wir immer noch die drei ABC-Transaktionen unter der obigen RR-Isolationsstufe als Beispiel

  • Vor dem Start von Transaktion A gibt es im System nur eine aktive Transaktion mit der ID 99, daher beträgt die Menge der aktiven Transaktionen zum Zeitpunkt des Starts von Transaktion A [99].
  • Die Versionsnummern der Transaktionen A, B und C lauten 100, 101 bzw. 102, und im aktuellen System gibt es nur diese vier Transaktionen, sodass die Höchststände der Transaktionen A, B und C jeweils 100, 101 und 102 lauten.
  • Vor dem Start der drei Transaktionen betrug die Zeile trx_id der Datenreihe (id,balance)=(1,1) den Wert 90.

Auf diese Weise ist die Konsistenzansicht der Transaktion A [99,100], die Konsistenzansicht der Transaktion B ist [99,100,101] und die Konsistenzansicht der Transaktion C ist [99,100,101,102]. Das heißt, die allgemeine Formel für die konsistente Ansicht lautet: [{die Menge der aktiven Transaktions-IDs zum Zeitpunkt des Öffnens der aktuellen Transaktion}, die aktuelle Zeile trx_id].

Analysieren Sie die Ergebnisse des obigen Flussdiagramms:

Die erste gültige Aktualisierungsversion ist Transaktion C, die den Saldo = 2 aktualisiert. Zu diesem Zeitpunkt ist die neueste Version rowtrx_id = 102, während die neueste Version rowtrx_id der vorherigen aktiven Transaktion vor Transaktion ABC 99 ist, sodass 99 zu diesem Zeitpunkt zur historischen Version 1 geworden ist.

Die zweite gültige Aktualisierungsversion ist Transaktion B, die den Saldo auf 3 aktualisiert. Zu diesem Zeitpunkt wird die neueste Version rowtrx_id=101 und rowtrx_id=102 zur historischen Version 1 und rowtrx_id=99 wird zur historischen Version 2.

Wenn Transaktion A abfragt, wurde Transaktion B nicht übermittelt, aber die generierte (ID, Saldo) = (1, 3) ist die neueste Version. Wenn Transaktion A Daten liest, ist die konsistente Ansicht [99, 100]. Die gelesenen Daten werden aus der aktuellen Version ausgeschnitten und dann mit der Zeile trx_id verglichen, sodass der folgende Prozess stattfindet:

  • Wenn (1,3) gefunden wird, wird festgestellt, dass die Zeile trx_id=101 größer als die Hochwassermarke ist, sich im roten Bereich befindet und nicht sichtbar ist;
  • Suchen Sie als Nächstes nach der vorherigen historischen Version und sehen Sie sich die Zeile trx_id=102 an, die größer als die Hochwassermarke ist und sich im roten Bereich befindet, sodass sie nicht sichtbar ist.
  • Wenn wir weiter nach vorne schauen, finden wir schließlich (1,1), dessen Zeile trx_id = 90, die kleiner als die Niedrigwassermarke ist und sich im grünen Bereich befindet, also sichtbar ist.

Unabhängig davon, wann Transaktion A abfragt, handelt es sich bei den Daten, die sie sieht, um die von der konsistenten Ansicht [99, 100] generierten Snapshot-Daten (1, 1), d. h. die Daten bei rowtrx_id = 90. Dies wird als konsistentes Lesen bezeichnet.

Zusammenfassen:

Für eine Transaktionsansicht gibt es neben der ständigen Sichtbarkeit ihrer eigenen Aktualisierungen drei weitere Situationen:

  • Die Version wurde nicht übermittelt und ist nicht sichtbar;
  • Die Version wurde übermittelt, sie wird jedoch erst nach der Erstellung der Ansicht übermittelt und ist nicht sichtbar.
  • Die Version wurde übermittelt und ist vor der Erstellung der Ansicht sichtbar.

Nun verwenden wir diese Regel, um die Abfrageergebnisse in der Abbildung zu beurteilen. Das Ansichtsarray der Abfrageanweisung von Transaktion A wird generiert, wenn Transaktion A gestartet wird. Zu diesem Zeitpunkt:

  • (1,3) wurde noch nicht übermittelt, gehört zum Fall 1 und ist nicht sichtbar;
  • (1,2) Obwohl es übermittelt wird, wird es nach der Erstellung des Ansichtsarrays übermittelt, das zu Fall 2 gehört und nicht sichtbar ist.
  • (1,1) wird übermittelt, bevor das Ansichtsarray erstellt und sichtbar ist.

3.4 Aktuelles Lesen und Snapshot-Lesen

3.4.1 Aktuelle Lese- und Snapshot-Leseregeln

Natürlich wird gemäß der Logik dieses konsistenten Lesens Transaktion B aktualisiert, nachdem Transaktion C effektiv den Saldo auf 2 aktualisiert hat, aber das Ansichtsarray von Transaktion B wird in Transaktion C generiert. Sollte Transaktion B also theoretisch nicht die Daten (ID, Saldo) = (1, 1) (Schnappschuss/historische Version) sehen? Die Daten der aktuellen Version (1, 2) sind nicht sichtbar. Warum werden die Daten der Transaktion B direkt nach der Aktualisierung des Saldos zu (1, 3)?

Wenn Transaktion B vor der Aktualisierung einmal Daten auswählt, sieht sie zwar den Wert „saldo=1“, aber die Aktualisierung kann nicht für die historische Version durchgeführt werden, da sonst die Aktualisierung von Transaktion C verloren geht. Daher liest der Aktualisierungsvorgang zuerst die aktuelle Version und führt dann die Aktualisierung durch.

Mit anderen Worten, es gibt eine Regel: Daten werden aktualisiert, indem zuerst gelesen und dann aktualisiert wird. Beim Lesen wird der neueste Wert gelesen, was als „aktueller Lesevorgang“ bezeichnet wird. Wenn Sie nur abfragen, ohne zu lesen, lesen Sie den aktuellen Snapshot, was als „Snapshot-Lesen“ bezeichnet wird. Bevor Transaktion B also den Kontostand aktualisiert, fragt sie zuerst die neueste Version (1, 2) ab und aktualisiert sie dann auf (1, 3). Die von Transaktion A abgefragten Snapshot-Daten sind (1, 1), nicht die neueste Version (1, 3).

3.4.2 Erklärung zu Current Read und Snapshot Read

Aktuelles Lesen: Vorgänge wie die Auswahlsperre im Freigabemodus (gemeinsame Sperre), die Auswahl zum Aktualisieren, Aktualisieren, Einfügen, Löschen (exklusive Sperre) sind alles aktuelle Lesevorgänge. Das heißt, es liest die neueste Version des Datensatzes. Beim Lesen muss sichergestellt werden, dass andere gleichzeitige Transaktionen den aktuellen Datensatz nicht ändern können und der gelesene Datensatz gesperrt wird.

Snapshot-Lesen: Ein entsperrter Auswahlvorgang ist ein Snapshot-Lesen, also ein entsperrtes, nicht blockierendes Lesen. Voraussetzung für ein Snapshot-Lesen ist, dass die Isolationsebene keine serielle Ebene ist. Ein Snapshot-Lesen auf serieller Ebene wird zu einem aktuellen Lesen degeneriert. Es basiert auf der Kontrolle mehrerer Versionen, sodass beim Lesen des Snapshots möglicherweise nicht die neueste Version der Daten gelesen wird, sondern es sich möglicherweise um eine frühere historische Version (Snapshot-Daten) handelt.

3.4.3 Regeln unter RC-Read-Commit anzeigen

Die Logik von Read Committed ähnelt der von Repeatable Read. Die Hauptunterschiede zwischen ihnen sind:

In der Isolationsstufe „Wiederholbares Lesen“ müssen Sie nur zu Beginn einer Transaktion eine konsistente Ansicht erstellen, und andere Abfragen in der Transaktion teilen sich diese konsistente Ansicht. In der Isolationsstufe „Read Committed“ wird vor der Ausführung jeder Anweisung eine neue Ansicht neu berechnet. In diesem Fall entspricht das Starten einer Transaktion mit konsistentem Snapshot dem normalen Starten einer Transaktion/Beginn. In der Isolationsstufe „RC“ lauten die von Transaktion A und Transaktion B abgefragten Daten also wie folgt:

Transaktion C aktualisiert sofort den Saldo = 2 und führt dann automatisch ein Commit aus, um die neueste Version (1, 2) zu generieren. Zu diesem Zeitpunkt werden die Ansichtsdaten (1, 2) neu berechnet. Transaktion B stellt fest, dass die neueste Version (1, 2) ist, und aktualisiert sie dann auf Version (1, 3) als neueste Version. Der von Transaktion B zu diesem Zeitpunkt ausgewählte Saldo ist 3 (nachdem Transaktion B den Saldo = 3 aktualisiert hat, wird sofort eine neue Ansicht berechnet und die Auswahl sind die basierend auf dieser Ansicht erhaltenen Daten), nicht 1. Zu diesem Zeitpunkt wurde Transaktion B noch nicht übermittelt und ist für Transaktion A unsichtbar, daher liest Transaktion A die neueste von Transaktion C übermittelte Version (1, 2).

Oben finden Sie eine kurze Analyse der Details zur Implementierung der Transaktionsisolierung durch MySQL. Weitere Informationen zur Transaktionsisolierung durch MySQL finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Beschreibung der Standardtransaktionsisolationsebene von MySQL und Oracle
  • Beispiel zum Anzeigen und Ändern der MySQL-Transaktionsisolationsebene
  • Detaillierte Erläuterung des Lese-Commits der MySQL-Transaktionsisolationsebene
  • Analyse der vier Transaktionsisolationsstufen in MySQL anhand von Beispielen
  • Detaillierte Erläuterung der vier Transaktionsisolationsebenen in MySQL
  • Detaillierte Erläuterung der Transaktionsisolierungsebenen der MySQL-Datenbank
  • Detaillierte Erklärung und Vergleich der vier Transaktionsisolationsebenen in MySQL
  • Detaillierte Analyse der MySQL-Transaktionsisolierung und ihrer Auswirkungen auf die Leistung
  • Tutorial zur Beziehung zwischen Innodb-Transaktionsisolationsebene und Sperre in MySQL
  • Einführung in die Transaktionsisolationsebene von MySQL-Datenbanken (Transaction Isolation Level)

<<:  Lösung für das CSS-Höhenkollapsproblem

>>:  Details zur Verwendung von Klassenstilen in Vue

Artikel empfehlen

Vue+Bootstrap realisiert ein einfaches Studentenverwaltungssystem

Ich habe Vue und Bootstrap verwendet, um ein rela...

So legen Sie Remotezugriffsberechtigungen in MySQL 8.0 fest

Im vorherigen Artikel wurde erklärt, wie man das ...

Detaillierte Erklärung der Rolle und des Prinzips des Schlüssels in Vue

Inhaltsverzeichnis 1. Beginnen wir mit dem Fazit ...

Praktische TypeScript-Tipps, die Sie vielleicht nicht kennen

Inhaltsverzeichnis Vorwort Funktionsüberladung Zu...

CentOS 7.x Docker verwendet die Overlay2-Speichermethode

Bearbeiten Sie /etc/docker/daemon.json und fügen ...

Grafisches Tutorial zur Installation und Konfiguration von MySQL 5.7.27

Detailliertes Download-, Installations- und Konfi...

Detaillierte Erklärung der RPM-Installation in MySQL

Installation und Deinstallation anzeigen # rpm -q...

Analyse des Hintergrundauthentifizierungsprozesses von Vue-Elementen

Vorwort: Kürzlich stieß ich in meinem Projekt auf...

XHTML-Erste-Schritte-Tutorial: Was ist XHTML?

Was ist HTML? Um es einfach auszudrücken: HTML wi...

Vue verwendet Regeln zur Implementierung der Formularfeldvalidierung

Es gibt viele Möglichkeiten, Formularfelder in Vu...

Mehrere Möglichkeiten zum Aktualisieren von Batches in MySQL

Normalerweise verwenden wir die folgende SQL-Anwe...