Kann die wiederholbare Leseebene von MySQL Phantomlesevorgänge lösen?

Kann die wiederholbare Leseebene von MySQL Phantomlesevorgänge lösen?

Einführung

Als ich mehr über die Datenbanktheorie erfuhr, erfuhr ich von den möglichen Problemen, die mit unterschiedlichen Isolationsstufen von Dingen verbunden sind. Zum besseren Verständnis haben wir diese Probleme in der MySQL-Datenbank getestet und reproduziert. Dirty Reads und nicht wiederholbare Reads können unter den entsprechenden Isolationsebenen problemlos reproduziert werden. Was Phantom-Lesevorgänge betrifft, stellte ich jedoch fest, dass diese unter der Isolationsstufe für wiederholbare Lesevorgänge nicht auftraten. Damals dachte ich, dass MySQL vielleicht etwas gegen Phantom-Lesevorgänge unternommen hat?

prüfen:

Erstellen Sie eine Testtabelle dept:

CREATE TABLE `dept` (
 `id` int(11) NICHT NULL AUTO_INCREMENT,
 `name` varchar(20) DEFAULT NULL,
 PRIMÄRSCHLÜSSEL (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8

insert into dept(name) values("Logistikabteilung")

Sache 1 Sache 2
beginnen beginnen
Wählen Sie * aus der Abteilung
- insert into dept(name) values("Forschungs- und Entwicklungsabteilung")
- begehen
Wählen Sie * aus der Abteilung
begehen

Gemäß dem obigen Prozess wird erwartet, dass die erste Auswahl von Transaktion 1 ein Datenelement abfragt und die zweite Auswahl zwei Datenelemente abfragt (einschließlich der von Transaktion 2 übermittelten Daten).

Allerdings stellte sich im Praxistest heraus, dass die zweite Auswahl tatsächlich nur ein Datenelement abfragt und verarbeitet. Gemäß der Implementierung des wiederholbaren Lesens in der Datenbanktheorie (exklusive Sperren und gemeinsam genutzte Sperren) sollte dies jedoch nicht der Fall sein.

Bevor wir die eigentlichen Gründe verstehen, wollen wir die relevanten Theorien dazu durchgehen.

Datenbankprinzipien Theorie

Ding

Mit Transaktion ist im Allgemeinen etwas gemeint, das getan werden muss oder erfolgt. In der Computersprache bezeichnet es eine Programmausführungseinheit, die auf verschiedene Datenelemente in einer Datenbank zugreift und diese ggf. aktualisiert. Eine Transaktion besteht aus allen Vorgängen, die zwischen dem Beginn und dem Ende einer Transaktion ausgeführt werden. In einer relationalen Datenbank kann eine Transaktion eine Reihe von SQL-Anweisungen oder ein ganzes Programm sein.

Warum haben wir Dinge?

Eine Datenbanktransaktion besteht typischerweise aus einer Folge von Operationen, die Lese- oder Schreibvorgänge in der Datenbank durchführen. Es dient zwei Zwecken:

  • Es bietet eine Methode, mit der Datenbankvorgänge nach einem Fehler wieder in den Normalzustand zurückversetzt werden können. Darüber hinaus bietet es eine Methode, mit der die Datenbank unter abnormalen Bedingungen ihre Konsistenz beibehalten kann.
  • Wenn mehrere Anwendungen gleichzeitig auf die Datenbank zugreifen, kann eine Isolationsmethode zwischen diesen Anwendungen bereitgestellt werden, um sicherzustellen, dass ihre Vorgänge sich nicht gegenseitig stören.

Eigenschaften der Dinge

Transaktionen haben vier Eigenschaften: Atomarität, Konsistenz, Isolation und Dauerhaftigkeit. Diese vier Eigenschaften werden oft als ACID-Eigenschaften bezeichnet.

  • Atomarität:
    Eine Transaktion sollte eine unteilbare Arbeitseinheit sein und die in der Transaktion enthaltenen Vorgänge sind entweder alle erfolgreich oder alle nicht erfolgreich.
  • Konsistenz:
    Eine Transaktion muss die Datenbank von einem konsistenten Zustand in einen anderen konsistenten Zustand ändern. Konsistenz und Atomarität hängen eng zusammen.
  • Isolierung:
    Die Ausführung einer Transaktion kann nicht durch andere Transaktionen gestört werden. Das heißt, dass die in einer Transaktion verwendeten Vorgänge und Daten vor der Festschreibung der Transaktion von anderen gleichzeitig ausgeführten Transaktionen isoliert werden und gleichzeitig ausgeführte Transaktionen sich nicht gegenseitig beeinflussen können.
  • Haltbarkeit:
    Sobald eine Transaktion erfolgreich abgeschlossen ist, sollten die an den Daten in der Datenbank vorgenommenen Änderungen dauerhaft sein. Nachfolgende andere Operationen oder Störungen sollten hierauf keinen Einfluss haben.

Einige Eigenschaften von Dingen stellen keine Menge gleichwertiger Konzepte dar:

Wenn zu einem bestimmten Zeitpunkt nur eine Sache vorhanden ist, ist diese natürlich isoliert, und Konsistenz kann erreicht werden, solange die Atomarität gewährleistet ist.

Bei Parallelität müssen Atomarität und Isolation gewährleistet sein, um die Konsistenz sicherzustellen.

Probleme bei gleichzeitigen Datenbanktransaktionen

Wenn die Transaktionsisolation nicht berücksichtigt wird, können die folgenden Probleme auftreten:

  • Dirty Read: Dirty Read bezieht sich auf das Lesen von Daten aus einer anderen nicht festgeschriebenen Transaktion während eines Transaktionsverarbeitungsprozesses. Wenn eine Transaktion ein Datenelement mehrmals ändert und diese Änderungen in dieser Transaktion noch nicht festgeschrieben wurden, sind die von den beiden Transaktionen erhaltenen Daten inkonsistent, wenn eine gleichzeitige Transaktion auf die Daten zugreift.
  • Nicht wiederholbares Lesen: Nicht wiederholbares Lesen bedeutet, dass für ein bestimmtes Datenelement in der Datenbank mehrere Abfragen innerhalb einer Transaktion unterschiedliche Datenwerte zurückgeben (wobei unterschiedlich bedeutet, dass der Inhalt eines oder mehrerer Datenelemente inkonsistent ist, die Anzahl der Datenelemente jedoch gleich ist). Dies liegt daran, dass während des Abfrageintervalls die von der Transaktion benötigten Daten von einer anderen Transaktion geändert und festgeschrieben wurden. Der Unterschied zwischen nicht wiederholbarem Lesen und Dirty Read besteht darin, dass Dirty Read vorliegt, wenn eine Transaktion schmutzige Daten liest, die nicht von einer anderen Transaktion festgeschrieben wurden, während nicht wiederholbares Lesen vorliegt, wenn Daten gelesen werden, die von anderen Transaktionen festgeschrieben wurden. Beachten Sie, dass nicht wiederholbare Lesevorgänge in einigen Fällen kein Problem darstellen.
  • Phantomlesen: Phantomlesen ist ein Phänomen, das auftritt, wenn Transaktionen nicht unabhängig ausgeführt werden. Beispielsweise ändert die Transaktion T1 ein Datenelement in allen Zeilen einer Tabelle von „1“ auf „2“. Zu diesem Zeitpunkt fügt die Transaktion T2 eine weitere Zeile mit Datenelementen in die Tabelle ein, und der Wert dieses Datenelements ist immer noch „1“ und wird an die Datenbank übermittelt. Wenn der Benutzer, der die Transaktion T1 ausführt, die gerade geänderten Daten überprüft, wird er feststellen, dass es noch eine Zeile gibt, die nicht geändert wurde. Tatsächlich wurde diese Zeile von der Transaktion T2 hinzugefügt, was wie eine Illusion ist. Dies ist ein Phantom-Lesevorgang. Sowohl Phantom-Lesevorgänge als auch nicht wiederholbare Lesevorgänge lesen eine andere festgeschriebene Transaktion (was sich von Dirty Reads unterscheidet). Der Unterschied besteht darin, dass nicht wiederholbare Lesevorgänge bei Aktualisierungs- und Löschvorgängen auftreten können, während Phantom-Lesevorgänge bei Einfügevorgängen auftreten.

Exklusive Sperre, gemeinsame Sperre

Exklusive Sperre, auch als X-Sperre bekannt, Schreibsperre.

Gemeinsam genutztes Schloss, auch als S-Schloss bekannt, Leseschloss.

Die Beziehung zwischen Lese-/Schreibsperren ist wie folgt:

  • Eine Transaktion fügt einem Datenobjekt O eine S-Sperre hinzu. Sie kann O lesen, aber nicht aktualisieren. Während der Sperrperiode können andere Transaktionen S-Sperren zu O hinzufügen, jedoch keine X-Sperren.
  • Eine Transaktion fügt einem Datenobjekt O eine X-Sperre hinzu und kann O lesen und aktualisieren. Während der Sperrfrist können andere Transaktionen keine Sperren zu O hinzufügen.

Das heißt, die Beziehung zwischen Lese- und Schreibsperren kann wie folgt zusammengefasst werden: Mehrfaches Lesen und einmaliges Schreiben

Isolationsstufe von Transaktionen

Bei Transaktionen gibt es mehrere Isolationsebenen:

  • Nicht festgeschrieben lesen: Lösen Sie das Problem verlorener Updates. Wenn eine Transaktion einen Schreibvorgang gestartet hat, dürfen andere Transaktionen nicht gleichzeitig schreiben, aber andere Transaktionen dürfen diese Datenzeile lesen. Diese Isolationsstufe kann durch eine "exklusive Schreibsperre" erreicht werden, d. h. wenn eine Transaktion bestimmte Daten ändern muss, muss sie den Daten eine X-Sperre hinzufügen und benötigt zum Lesen der Daten keine S-Sperre.
  • Read Committed: Lösen Sie das Dirty-Read-Problem. Transaktionen, die Daten lesen, ermöglichen anderen Transaktionen den weiteren Zugriff auf die Datenzeile. Nicht festgeschriebene Schreibtransaktionen verhindern jedoch, dass andere Transaktionen auf die Zeile zugreifen. Dies kann durch „sofortige gemeinsame Lesesperre“ und „exklusive Schreibsperre“ erreicht werden, d. h. wenn eine Transaktion bestimmte Daten ändern muss, muss den Daten eine X-Sperre hinzugefügt werden und beim Lesen der Daten muss eine S-Sperre hinzugefügt werden. Wenn die Daten gelesen werden, wird die S-Sperre sofort freigegeben, ohne auf das Ende der Transaktion zu warten.
  • Wiederholbares Lesen: Nicht wiederholbares Lesen und Dirty Read sind verboten, aber Phantomlesen kann manchmal vorkommen. Transaktionen, die Daten lesen, verbieten Schreibtransaktionen (lassen aber Lesetransaktionen zu), und Schreibtransaktionen verbieten alle anderen Transaktionen. Mysql verwendet standardmäßig diese Isolationsebene. Dies kann durch „gemeinsame Lesesperre“ und „exklusive Schreibsperre“ erreicht werden, d. h. wenn eine Transaktion bestimmte Daten ändern muss, muss den Daten eine X-Sperre hinzugefügt werden und beim Lesen von Daten muss eine S-Sperre hinzugefügt werden. Beim Lesen der Daten wird die S-Sperre nicht sofort freigegeben, sondern erst nach Abschluss der Transaktion.
  • Serialisierbar: Lösen Sie das Problem des Phantomlesens. Bietet strikte Transaktionsisolierung. Dabei ist es erforderlich, dass Transaktionen seriell ausgeführt werden. Transaktionen können nur nacheinander und nicht gleichzeitig ausgeführt werden. Die Serialisierung von Transaktionen kann nicht einfach durch „Sperren auf Zeilenebene“ erreicht werden. Es müssen andere Mechanismen verwendet werden, um sicherzustellen, dass neu eingefügte Daten nicht von der Transaktion abgerufen werden, die gerade den Abfragevorgang ausgeführt hat.

Implementierung von Isolationsebenen in MySQL

Der obige Inhalt erläutert einige Konzepte der Datenbanktheorie. In Datenbanken wie MySQL und ORACLE werden sie jedoch aus Leistungsgründen nicht vollständig gemäß den oben vorgestellten Theorien implementiert.

MVCC

Multi-Version Concurrency Control (MVCC) ist eine Methode zur Implementierung von Isolationsebenen in MySQL basierend auf der Theorie optimistischer Sperren. Sie wird zur Implementierung von Read-Commit- und Repeatable-Read-Isolationsebenen verwendet.

Implementierung (Isolationsebene ist wiederholbares Lesen)

Bevor wir über die Implementierung sprechen, stellen wir zwei Konzepte vor:

Systemversionsnummer: Eine steigende Zahl. Die Systemversionsnummer wird automatisch erhöht, wenn eine neue Transaktion gestartet wird.

Transaktionsversionsnummer: Die Systemversionsnummer beim Start der Transaktion.

In MySQL werden nach jedem Datensatz in der Tabelle zwei Felder hinzugefügt:

Versionsnummer erstellen: Beim Erstellen einer Datenzeile wird die aktuelle Systemversionsnummer als Erstellungsversionsnummer zugewiesen.

Versionsnummer löschen: Beim Löschen einer Datenzeile wird die aktuelle Systemversionsnummer als Löschversionsnummer vergeben

WÄHLEN

Für das Lesen der Daten während der Auswahl gilt die Regel: Die Erstellungsversionsnummer <= die aktuelle Transaktionsversionsnummer und die Löschversionsnummer ist leer oder > die aktuelle Transaktionsversionsnummer.

Die Erstellungsversionsnummer <= aktuelle Transaktionsversionsnummer stellt sicher, dass die abgerufenen Daten keine Daten enthalten, die in später gestarteten Transaktionen erstellt wurden. Aus diesem Grund sind die nachträglich hinzugefügten Daten im ersten Beispiel nicht vorhanden.

Die Löschversionsnummer ist leer oder > der aktuellen Transaktionsversionsnummer. Dadurch wird sichergestellt, dass die Daten zumindest vor dem Start der Transaktion nicht gelöscht wurden und es sich um Daten handelt, die ausgecheckt werden sollten.

EINFÜGEN

Beim Einfügen ist im Feld Erstellungsversionsnummer die aktuelle Systemversionsnummer zuzuweisen.

AKTUALISIEREN

Fügen Sie einen neuen Datensatz ein, speichern Sie die aktuelle Transaktionsversionsnummer als Zeilenerstellungsversionsnummer und speichern Sie die aktuelle Transaktionsversionsnummer in der ursprünglich gelöschten Zeile. Tatsächlich wird das Update hier durch Löschen und Einfügen implementiert.

LÖSCHEN

Beim Löschen wird dem Feld „Löschversionsnummer“ die aktuelle Systemversionsnummer zugewiesen, um anzugeben, in welcher Transaktion die Datenzeile gelöscht wird, auch wenn die Daten beim Ausführen des Commits nicht tatsächlich gelöscht werden. Die Daten werden nicht gefunden, auch wenn sie entsprechend der Auswahlregel geöffnet werden.

Löst MVCC wirklich das Phantomlesen?

Aus unseren ersten Testbeispielen und der oben genannten theoretischen Unterstützung geht hervor, dass das Phantomleseproblem durch MVCC in MySQL gelöst wurde. Da serielles Lesen sinnlos erscheint, testen wir mit Zweifeln weiter.

Daten vor dem Test:

Sache 1 Sache 2
beginnen beginnen
Wählen Sie * aus der Abteilung
- insert into dept(name) values("Forschungs- und Entwicklungsabteilung")
- begehen
update dept set name="Finanzabteilung" (Wenn Sie nicht gefeuert werden möchten, müssen Sie die Where-Bedingung schreiben)
begehen

Basierend auf den obigen Ergebnissen erwarten wir das folgende Ergebnis:

ID-Name
1 Finanzabteilung
2 Forschungs- und Entwicklungsabteilung

Tatsächlich ist unsere Erfahrung jedoch:

Ursprünglich hatten wir gehofft, die Abteilung der ersten Daten in „Finanzen“ ändern zu können, letztendlich wurden jedoch beide Daten geändert. Dieses Ergebnis zeigt uns, dass die wiederholbare Leseisolationsebene von MySQL das Problem der Phantomlesevorgänge nicht vollständig löst, jedoch das Phantomleseproblem beim Lesen von Daten löst. Bei Änderungsvorgängen besteht jedoch weiterhin das Phantomleseproblem. Dies bedeutet, dass die MVCC-Lösung für Phantomlesevorgänge nicht gründlich ist.

Snapshot-Lesen und aktuelles Lesen

Wenn die oben beschriebene Situation eintritt, müssen wir wissen, warum sie auftritt. Nachdem ich einige Informationen konsultiert hatte, stellte ich fest, dass es sich bei den von uns gelesenen Daten auf RR-Ebene zwar aufgrund des MVCC-Mechanismus um historische Daten und nicht um die neuesten Daten in der Datenbank handeln kann, die Daten auf RR-Ebene jedoch wiederholbar sind. Diese Methode zum Lesen historischer Daten wird als Snapshot-Lesen bezeichnet, und die Methode zum Lesen der neuesten Version der Datenbank wird als aktuelles Lesen bezeichnet.

Snapshot auswählen lesen

Beim Ausführen einer Auswahloperation führt InnoDB standardmäßig einen Snapshot-Lesevorgang durch und zeichnet das Ergebnis dieser Auswahl auf. Die Daten dieses Snapshots werden in nachfolgenden Auswahlvorgängen zurückgegeben. Selbst wenn andere Transaktionen festgeschrieben werden, hat dies keine Auswirkungen auf die Daten der aktuellen Auswahl, sodass ein wiederholbares Lesen erreicht wird. Der Snapshot wird generiert, wenn select zum ersten Mal ausgeführt wird. Das heißt, angenommen, A startet eine Transaktion und führt dann keine Operationen aus. Zu diesem Zeitpunkt fügt B ein Datenelement ein und übergibt es. Zu diesem Zeitpunkt führt A select aus, dann enthalten die zurückgegebenen Daten die von B hinzugefügten Daten. Es spielt keine Rolle, ob anschließend andere Transaktionen festgeschrieben werden, da der Snapshot generiert wurde und nachfolgende Auswahlen auf dem Snapshot basieren.

Aktueller Messwert

Für Vorgänge, die Daten ändern (Aktualisieren, Einfügen, Löschen), wird der aktuelle Lesemodus verwendet. Beim Ausführen dieser Vorgänge werden die neuesten Datensätze gelesen und sogar von anderen Transaktionen übermittelte Daten können abgefragt werden. Angenommen, Sie möchten einen Datensatz aktualisieren, aber die Daten wurden gelöscht und in einer anderen Transaktion festgeschrieben. Wenn Sie ihn aktualisieren, tritt ein Konflikt auf. Daher müssen Sie beim Aktualisieren die neuesten Daten kennen. Genau aus diesem Grund ist die oben getestete Situation eingetreten.

Das aktuelle Lesen von Select muss manuell gesperrt werden:

Wählen Sie * aus der Tabelle, wo? Im Freigabemodus sperren;
Wählen Sie * aus der Tabelle, wobei ? für die Aktualisierung steht;

Es gibt ein Problem zu erklären

Zu Beginn des Tests dachte ich, dass die Verwendung der Begin-Anweisung dazu dient, eine Transaktion zu starten. Im zweiten Test oben wurden die neu hinzugefügten Daten von Transaktion 2 in Transaktion 1 gefunden, da Transaktion 1 zuerst gestartet wurde. Zu diesem Zeitpunkt dachte ich, dass dies nicht mit den Auswahlregeln im vorherigen MVCC übereinstimmte, also führte ich den folgenden Test durch:

SELECT * FROM information_schema.INNODB_TRX //Wird verwendet, um die aktuell ausgeführte Transaktion abzufragen

Es ist ersichtlich, dass eine Transaktion nicht wirklich gestartet wird, wenn Sie nur die Begin-Anweisung ausführen.

Fügen Sie als Nächstes nach „begin“ eine Select-Anweisung hinzu:

Daher ist es wichtig zu verstehen, dass eine Transaktion erst dann tatsächlich eröffnet wird, wenn Vorgänge wie das Hinzufügen, Löschen, Ändern und Überprüfen der Daten durchgeführt wurden.

So lösen Sie Phantom-Reads

Offensichtlich kann die wiederholbare Leseisolationsebene das Problem des Phantomlesens nicht vollständig lösen. Wenn wir Phantomlesen in unserem Projekt lösen müssen, gibt es zwei Möglichkeiten:

  • Verwenden der serialisierbaren Leseisolationsebene
  • MVCC+Next-Key-Locks: Next-Key-Locks bestehen aus Record-Locks (Index-Locks) und Gap-Locks (Lücken-Locks, die nicht nur die jeweils zu verwendenden Daten, sondern auch die Daten in der Nähe dieser Daten sperren)

Tatsächlich werden die beiden oben genannten Methoden in vielen Projekten nicht verwendet. Die Leistung des serialisierten Lesens ist zu schlecht, und tatsächlich ist das Phantomlesen für uns oft völlig akzeptabel.

Zusammenfassen

Das Obige ist der vollständige Inhalt dieses Artikels. Ich hoffe, dass der Inhalt dieses Artikels einen gewissen Lernwert für Ihr Studium oder Ihre Arbeit hat. Vielen Dank für Ihre Unterstützung von 123WORDPRESS.COM.

Das könnte Sie auch interessieren:
  • Beispiel für die Verwendung von MySQL-Transaktionsfunktionen zur Implementierung einer gleichzeitigen und sicheren Auto-Increment-ID
  • Lösung für das Problem der gesperrten Transaktionsverarbeitung mit hoher Parallelität in PHP+MySQL
  • Detaillierte Erklärung, wie MySQL Phantom-Lesevorgänge löst
  • Lösung für das Problem der MySQL-Transaktionsparallelität
  • Detaillierte Erklärung zu MySQL-Phantomlesevorgängen und wie man sie eliminiert
  • MySQL Series 10 MySQL-Transaktionsisolierung zur Implementierung der Parallelitätskontrolle
  • So lösen Sie das Phantomleseproblem in MySQL
  • mysql + mybatis implementiert gespeicherte Prozedur + Transaktion + gleichzeitigen Mehrfachabruf von Seriennummern
  • Detaillierte Erläuterung des gleichzeitigen Dirty Read + nicht wiederholbaren Read + Phantom Read in MySQL-Transaktionen

<<:  Docker installiert und führt den RabbitMQ-Beispielcode aus

>>:  Detaillierte Erklärung zur Installation und Verwendung von Vue-Router

Artikel empfehlen

js, um die Rotation von Webseitenbildern zu realisieren

In diesem Artikel wird der spezifische Code von j...

Datensatz zu langsamen MySQL-Abfragen und Abfragerekonstruktionsmethoden

Vorwort Was ist eine langsame Abfrage und wie kan...

Beispiel für die Anpassung des Vue-Projekts an den großen Bildschirm

Eine kurze Analyse von rem Zunächst einmal ist re...

So starten und starten Sie nginx unter Linux neu

Nginx (Engine x) ist ein leistungsstarker HTTP- u...

Lösen Sie das Problem der inkonsistenten MySQL-Speicherzeit

Nachdem die Systemzeit mit Java ermittelt und in ...

Linux-Installation Redis-Implementierungsprozess und Fehlerlösung

Ich habe heute Redis installiert und es sind eini...

Schreiben eines Schere-Stein-Papier-Spiels in JavaScript

In diesem Artikel finden Sie den spezifischen Cod...

Neue Funktionen in MySQL 8.0: Hash Join

Das MySQL-Entwicklungsteam hat am 14. Oktober 201...

So leiten Sie den Nginx-Verzeichnispfad um

Wenn der Pfad nach dem Domänennamen auf andere Ve...

js Drag & Drop-Tabelle zur Realisierung der Inhaltsberechnung

In diesem Artikelbeispiel wird der spezifische Co...

10 beliebte Windows-Apps, die auch unter Linux verfügbar sind

Laut dem Datenanalyseunternehmen Net Market Share...

Warum wird deine Like-Aussage nicht indexiert?

Vorwort Dieser Artikel zielt darauf ab, die langw...