Detailliertes Beispiel des MySQL InnoDB-Sperrmechanismus

Detailliertes Beispiel des MySQL InnoDB-Sperrmechanismus

1. InnoDB-Sperrmechanismus

Die InnoDB-Speicher-Engine unterstützt Zeilensperren und Transaktionsverarbeitung. Eine Transaktion ist eine logische Verarbeitungseinheit, die aus einer Gruppe von SQL-Anweisungen besteht. Ihre ACID-Eigenschaften sind wie folgt:

  • Atomarität: Transaktionen sind atomar und unteilbar und werden entweder gemeinsam oder gar nicht ausgeführt.
  • Konsistenz: Die Daten bleiben zu Beginn und am Ende einer Transaktion in einem konsistenten Zustand.
  • Isolierung: Während des Starts und Endes einer Transaktion behält die Transaktion bestimmte Isolierungsmerkmale bei, um sicherzustellen, dass die Transaktion nicht durch externe, gleichzeitige Datenvorgänge beeinträchtigt wird.
  • Dauerhaftigkeit: Nachdem die Transaktion abgeschlossen ist, bleiben die Daten in der Datenbank gespeichert.

Gleichzeitige Transaktionen können die Nutzung von Datenbankressourcen verbessern und den Transaktionsdurchsatz der Datenbank erhöhen. Gleichzeitige Transaktionen bringen jedoch auch einige Probleme mit sich, vor allem:

  • Verlorenes Update: Zwei Transaktionen aktualisieren dieselben Daten, aber die zweite Transaktion schlägt fehl und wird auf halbem Weg beendet, wodurch beide Änderungen ungültig werden. Da die Datenbank zu diesem Zeitpunkt keine Sperrvorgänge durchführt, werden gleichzeitige Transaktionen nicht isoliert. (Dieses Problem besteht in modernen Datenbanken nicht mehr)
  • Dirty Reads: Eine Transaktion liest eine Datenzeile, aber eine andere Transaktion hat diese Datenzeile bereits aktualisiert. Dies ist sehr gefährlich und kann dazu führen, dass alle Vorgänge rückgängig gemacht werden.
  • Nicht wiederholbares Lesen: Eine Transaktion liest eine Datenzeile zweimal (oder öfter), erhält aber unterschiedliche Ergebnisse. Während der beiden Lesevorgänge ist es möglich, dass eine andere Transaktion die Daten geändert hat.
  • Phantomlesen: Eine Transaktion führt während des Vorgangs zwei Abfragen aus und das Ergebnis der zweiten Abfrage enthält Daten, die in der ersten Abfrage nicht vorkamen. Der Hauptgrund für Phantom-Lesevorgänge besteht darin, dass während der beiden Abfrageprozesse eine andere Transaktion neue Daten einfügt.

„Updateverlust“ bei parallelen Datenbankzugriffen sollte normalerweise vollständig vermieden werden, aber der Verlust von Updatedaten kann nicht allein durch die Transaktionskontrolle der Datenbank verhindert werden. Die Anwendung muss den zu aktualisierenden Daten die erforderlichen Sperren hinzufügen. Die oben genannten Datenbankprobleme müssen gelöst werden, indem die Datenbank einen bestimmten Transaktionsisolierungsmechanismus bereitstellt. Um Probleme durch gleichzeitige Datenbanktransaktionen zu vermeiden, sind in der Standard-SQL-Spezifikation vier Transaktionsisolationsebenen definiert. Unterschiedliche Isolationsebenen behandeln Transaktionen unterschiedlich.

Vergleich der Datenbankisolationsebenen

Isolationsstufe Konsistenz der Lesedaten Schmutzige Lektüre Nicht wiederholbares Lesen Phantom lesen
Nicht festgeschrieben lesen
(Nicht festgeschrieben lesen)
Die niedrigste Stufe, die nur garantiert, dass physisch beschädigte Daten nicht gelesen werden Ja Ja Ja
Lesen Sie Commitment
(Lesen Sie es selbst)
Anweisungsebene NEIN Ja Ja
Wiederholbares Lesen
(Wiederholbares Lesen)
Transaktionsebene NEIN NEIN Ja
Serialisierbar
(Serialisierbar)
Höchste Ebene, Transaktionsebene NEIN NEIN NEIN

Die InnoDB-Speicher-Engine implementiert vier Arten von Zeilensperren: gemeinsame Sperre (S), exklusive Sperre (X), beabsichtigte gemeinsame Sperre (IS) und beabsichtigte exklusive Sperre (IX).

  • Gemeinsames Schloss: Jeder kann lesen, aber nicht ändern. Nur einer kann Änderungen vornehmen, wenn er das exklusive gemeinsame Schloss besitzt.
  • Exklusive Sperre: Ich möchte es ändern, aber Sie können es nicht ändern oder lesen (Sie können es jedoch mit dem MVCC-Snapshot lesen).

Absichtssperren verstehen

Absichtssperren stehen nicht im Konflikt mit S- und X-Sperren auf Zeilenebene, sondern nur mit S- und X-Sperren auf Tabellenebene.

Die Absicht der Sperre besteht darin, das Durchlaufen aller Zeilensperren zu vermeiden

Betrachten Sie dieses Beispiel:

Transaktion A sperrt eine Zeile in der Tabelle, sodass sie lesbar, aber nicht beschreibbar ist.

Anschließend beantragt Transaktion B eine Schreibsperre für die gesamte Tabelle.

Wenn Transaktion B erfolgreich ist, kann sie theoretisch jede Zeile in der Tabelle ändern, was im Konflikt mit der von A gehaltenen Zeilensperre steht.

Die Datenbank muss diesen Konflikt vermeiden, was bedeutet, dass die Anwendung von B blockiert werden muss, bis A die Zeilensperre freigibt.

Wie stellt die Datenbank diesen Konflikt fest?

Schritt 1: Bestimmen Sie, ob die Tabelle durch andere Transaktionen gesperrt wurde

Schritt 2: Bestimmen Sie, ob jede Zeile in der Tabelle durch eine Zeilensperre gesperrt ist.

Beachten Sie Schritt 2. Diese Beurteilungsmethode ist nicht sehr effizient, da die gesamte Tabelle durchlaufen werden muss.

Es liegt also eine Absichtssperre vor.

Wenn eine Absichtssperre vorhanden ist, muss Transaktion A zuerst eine Absichtssperre für die Tabelle beantragen und dann bei Erfolg eine Zeilensperre für eine Zeile.

Im Falle einer Absichtssperre kann das obige Urteil geändert werden in

Schritt 1: unverändert

Schritt 2: Es wird festgestellt, dass die Tabelle absichtlich mit einer gemeinsamen Sperre belegt ist. Das bedeutet, dass einige Zeilen in der Tabelle durch eine gemeinsame Zeilensperre gesperrt sind. Daher wird die Anwendung einer Schreibsperre für die Tabelle durch Transaktion B blockiert.

1.1 Daten über Index abrufen, gemeinsame Sperre und Zeilensperre anwenden (wenn nicht über Index, wird Tabellensperre verwendet)

1.1 Daten über Index abrufen, gemeinsame Sperre und Zeilensperre setzen SessionA SessionB
mysql> setze Autocommit=0; mysql> setze Autocommit=0;
Abfrage OK, 0 Zeilen betroffen (0,02 Sek.) Abfrage OK, 0 Zeilen betroffen (0,02 Sek.)
mysql> wähle * aus Test; mysql> wähle * aus Test;
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+-------+----------+----------+              
| ID | Name | Geld | Stufe | | ID | Name | Geld | Stufe |
+----+-------+-------+-------+ +----+-------+----------+----------+
| 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 |
| 2 | Buchse | 200 | 2 | | 2 | Buchse | 200 | 2 |
| 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 |
+----+-------+-------+-------+ +----+-------+----------+----------+
3 Zeilen im Set (0,00 Sek.) 3 Zeilen im Set (0,00 Sek.)
--------------------------------------------------------------------------------
Gemeinsame Sperre für den Primärschlüsselindex, andere Transaktionen können ebenfalls eine gemeinsame Sperre erhalten mysql> select * from test where         
id=1 Sperre im Freigabemodus;
+----+------+-------+---------+
| ID | Name | Geld | Stufe |
+----+------+-------+---------+
| 1 | tom | 100 | 1 |
+----+------+-------+---------+
1 Zeile im Satz (0,01 Sek.)
--------------------------------------------------------------------------------
                        Transaktion B kann auch weiterhin gemeinsam genutzte Sperren hinzufügenmysql> select * from test where         
                        id=1 Sperre im Freigabemodus;
                        +----+------+-------+---------+
                        | ID | Name | Geld | Stufe |
                        +----+------+-------+---------+
                        | 1 | tom | 100 | 1 |
                        +----+------+-------+---------+
                        1 Zeile im Satz (0,01 Sek.)
                        Es kann jedoch nicht aktualisiert werden, da Transaktion A auch ein gemeinsames lockmysql> update test set level=11 where id=1; hinzufügt.
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
                        
                        MEHR:
                        Exklusive Sperre „Select *from test“ mit ID=1 kann für Update nicht hinzugefügt werden;
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
                        
                        Sie können entsperrte aktualisieren, zum Beispiel mit mysql> update test set level=11 where id=2;
                        Abfrage OK, 1 Zeile betroffen (0,00 Sek.)
                        Übereinstimmende Zeilen: 1 Geändert: 1 Warnungen: 0
--------------------------------------------------------------------------------
Transaktion A kann auch nicht aktualisiert werden, da Transaktion B ein gemeinsames lockmysql> update test set level=11 where id=1; hinzufügt.
FEHLER 1205 (HY000): Wartezeit für Sperre überschritten
ded; versuche die Transaktion neu zu starten
--------------------------------------------------------------------------------
                        Wenn irgendjemand die gemeinsam genutzte Sperre freigibt, kann die Transaktion, die ausschließlich die gemeinsam genutzte Sperre hält, mysql> commit aktualisieren;
                        Abfrage OK, 0 Zeilen betroffen (0,00 Sek.)
--------------------------------------------------------------------------------
Transaktion B gibt die Sperre frei, und Transaktion A hat den alleinigen Besitz und kann update.mysql> update test set level=11 where id=1;
Abfrage OK, 1 Zeile betroffen (0,00 Sek.)
Übereinstimmende Zeilen: 1 Geändert: 1 Warnungen: 0

1.2 Daten über Index abrufen, exklusive Sperre und Zeilensperre festlegen

1.2 Daten über Index abrufen, exklusive Sperre und Zeilensperre setzen SessionA SessionB
mysql> setze Autocommit=0; mysql> setze Autocommit=0;
Abfrage OK, 0 Zeilen betroffen (0,02 Sek.) Abfrage OK, 0 Zeilen betroffen (0,02 Sek.)
mysql> wähle * aus Test; mysql> wähle * aus Test;
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+-------+----------+----------+              
| ID | Name | Geld | Stufe | | ID | Name | Geld | Stufe |
+----+-------+-------+-------+ +----+-------+----------+-----------+
| 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 |
| 2 | Buchse | 200 | 2 | | 2 | Buchse | 200 | 2 |
| 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 |
+----+-------+-------+-------+ +----+-------+----------+----------+
3 Zeilen im Set (0,00 Sek.) 3 Zeilen im Set (0,00 Sek.)
--------------------------------------------------------------------------------
Exklusive Sperre für den Primärschlüsselindex, andere Transaktionen können auch gemeinsame Sperren erhalten mysql> select * from test where
id=1 für Update;
+----+------+-------+---------+
| ID | Name | Geld | Stufe |
+----+------+-------+---------+
| 1 | tom | 100 | 1 |
+----+------+-------+---------+
1 Zeile im Satz (0,01 Sek.)
--------------------------------------------------------------------------------
                        Transaktion B kann keine exklusiven Sperren mehr erwerben und wartet für das Update auf „mysql> select *from test where id=1“.
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
                        
                        MEHR:
                        Es ist auch kein Update möglich, da durch das Update auch eine exklusive Sperre gesetzt wird mysql> update test set level=2 where id=1;
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
                        
                        mysql> select * from test where level=1 lock in share mode;
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
--------------------------------------------------------------------------------
Transaktion A kann updatemysql> Testsatzlevel=11 aktualisieren, wobei ID=1 ist;
Abfrage OK, 1 Zeile betroffen (0,08 Sek.)
Übereinstimmende Zeilen: 1 Geändert: 1 Warnungen: 0
--------------------------------------------------------------------------------
Geben Sie die exklusive Sperre frei mysql> commit;
Abfrage OK, 0 Zeilen betroffen (0,00 Sek.)
--------------------------------------------------------------------------------
                        Transaktion A gibt die Sperre frei und Transaktion B kann eine exklusive Sperre hinzufügenmysql> select * from test where id=1 for update;
                        +----+------+-------+---------+
                        | ID | Name | Geld | Stufe |
                        +----+------+-------+---------+
                        | 1 | tom | 100 | 1 |
                        +----+------+-------+---------+
                        1 Zeile im Satz (0,00 Sek.)

1.3 Aktualisieren Sie die Daten über den Index und setzen Sie außerdem eine exklusive Sperre und eine Zeilensperre

Für Update-, Insert- und Delete-Anweisungen wird automatisch eine exklusive Sperre hinzugefügt

1.3 Daten über den Index aktualisieren, außerdem exklusive Sperre und Zeilensperre festlegen SessionA SessionB
mysql> setze Autocommit=0; mysql> setze Autocommit=0;
Abfrage OK, 0 Zeilen betroffen (0,02 Sek.) Abfrage OK, 0 Zeilen betroffen (0,02 Sek.)
mysql> wähle * aus Test; mysql> wähle * aus Test;
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+-------+----------+-----------+              
| ID | Name | Geld | Stufe | | ID | Name | Geld | Stufe |
+----+-------+-------+-------+ +----+-------+----------+----------+
| 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 |
| 2 | Buchse | 200 | 2 | | 2 | Buchse | 200 | 2 |
| 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 |
+----+-------+-------+-------+ +----+-------+----------+----------+
3 Zeilen im Set (0,00 Sek.) 3 Zeilen im Set (0,00 Sek.)
--------------------------------------------------------------------------------
Beim Aktualisieren der Zeile mit der ID=1 wird eine exklusive Sperre auf die Zeile gesetzt und andere Transaktionen können die Zeile nicht aktualisieren. mysql> update test set level=11 where id=1;
Abfrage OK, 1 Zeile betroffen (0,00 Sek.)
Übereinstimmende Zeilen: 1 Geändert: 1 Warnungen: 0
--------------------------------------------------------------------------------
                        Transaktion B kann die Zeile mit der ID=1 nicht aktualisieren und wartet auf mysql> update test set level=21 where id=1;
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
                        
                        MEHR:
                        Sie können keine exklusive Sperre festlegen mysql> select *from test where id=1 for update;
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
                        
                        mysql> select * from test where level=1 lock in share mode;
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
--------------------------------------------------------------------------------
Geben Sie die exklusive Sperre frei mysql> commit;
Abfrage OK, 0 Zeilen betroffen (0,00 Sek.)
--------------------------------------------------------------------------------
                        Transaktion A gibt die Sperre frei und Transaktion B kann eine exklusive Sperre hinzufügenmysql> select * from test where id=1 for update;
                        +----+------+-------+---------+
                        | ID | Name | Geld | Stufe |
                        +----+------+-------+---------+
                        | 1 | tom | 100 | 11|
                        +----+------+-------+---------+
                        1 Zeile im Satz (0,00 Sek.)

2.1 Schmutziges Lesen

//Dirty Read //2.1 Dirty Read SitzungA SitzungB
mysql> setze Autocommit=0; mysql> setze Autocommit=0;
Abfrage OK, 0 Zeilen betroffen (0,02 Sek.) Abfrage OK, 0 Zeilen betroffen (0,02 Sek.)
Isolation für Sitzungstransaktionen festlegen Isolationsebene für Sitzungstransaktionen festlegen Nicht festgeschriebenes Lesen;
Leseebene nicht festgeschrieben; Abfrage OK, 0 Zeilen betroffen (0,00 Sek.)
Abfrage OK, 0 Zeilen betroffen (0,00 Sek.)      
mysql> wähle * aus Test; mysql> wähle * aus Test;
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+-------+----------+----------+              
| ID | Name | Geld | Stufe | | ID | Name | Geld | Stufe |
+----+-------+-------+-------+ +----+-------+----------+-----------+
| 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 |
| 2 | Buchse | 200 | 2 | | 2 | Buchse | 200 | 2 |
| 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 |
+----+-------+-------+-------+ +----+-------+----------+----------+
3 Zeilen im Set (0,00 Sek.) 3 Zeilen im Set (0,00 Sek.)
--------------------------------------------------------------------------------
                        mysql> Testsatz aktualisieren, Level=100, wobei ID=1;
                        Abfrage OK, 1 Zeile betroffen (0,00 Sek.)
                        Übereinstimmende Zeilen: 1 Geändert: 1 Warnungen: 0
--------------------------------------------------------------------------------
// Schmutziges readmysql> Wählen Sie *aus Test aus, wobei ID=1;
+----+------+-------+---------+
| ID | Name | Geld | Stufe |
+----+------+-------+---------+
| 1 | tom | 100 | 100 |
+----+------+-------+---------+
1 Zeile im Satz (0,00 Sek.)
--------------------------------------------------------------------------------
                        zurückrollen;
                        Abfrage OK, 0 Zeilen betroffen (0,01 Sek.)
                        
                        mysql> Auswahl *aus Test, wobei ID=1;
                        +----+------+-------+---------+
                        | ID | Name | Geld | Stufe |
                        +----+------+-------+---------+
                        | 1 | tom | 100 | 1 |
                        +----+------+-------+---------+
                        1 Zeile im Satz (0,00 Sek.)

2.2 Nicht wiederholbares Lesen

2.2 Nicht wiederholbares Lesen // Dirty Read SessionA SessionB
mysql> setze Autocommit=0; mysql> setze Autocommit=0;
Abfrage OK, 0 Zeilen betroffen (0,02 Sek.) Abfrage OK, 0 Zeilen betroffen (0,02 Sek.)
Isolation für Sitzungstransaktionen festlegen Isolationsebene für Sitzungstransaktionen festlegen Nicht festgeschriebenes Lesen;
Leseebene nicht festgeschrieben; Abfrage OK, 0 Zeilen betroffen (0,00 Sek.)
Abfrage OK, 0 Zeilen betroffen (0,00 Sek.)      
mysql> wähle * aus Test; mysql> wähle * aus Test;
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+-------+----------+----------+              
| ID | Name | Geld | Stufe | | ID | Name | Geld | Stufe |
+----+-------+-------+-------+ +----+-------+----------+----------+
| 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 |
| 2 | Buchse | 200 | 2 | | 2 | Buchse | 200 | 2 |
| 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 |
+----+-------+-------+-------+ +----+-------+----------+----------+
3 Zeilen im Set (0,00 Sek.) 3 Zeilen im Set (0,00 Sek.)
--------------------------------------------------------------------------------
                        mysql> Testsatz aktualisieren, Level=100, wobei ID=1;
                        Abfrage OK, 1 Zeile betroffen (0,00 Sek.)
                        Übereinstimmende Zeilen: 1 Geändert: 1 Warnungen: 0
--------------------------------------------------------------------------------
mysql> Auswahl *aus Test, wobei ID=1;
+----+------+-------+---------+
| ID | Name | Geld | Stufe |
+----+------+-------+---------+
| 1 | tom | 100 | 100 |
+----+------+-------+---------+
1 Zeile im Satz (0,00 Sek.)
--------------------------------------------------------------------------------
                        mysql> Testsatz aktualisieren, Level=1000, wobei ID=1;
                        Abfrage OK, 1 Zeile betroffen (0,00 Sek.)
                        Übereinstimmende Zeilen: 1 Geändert: 1 Warnungen: 0
--------------------------------------------------------------------------------
// Nicht wiederholbares Lesen // Dreimal lesen, das erste Mal ist Stufe 1, das zweite Mal ist 100 und das dritte Mal ist 1000
mysql> Auswahl *aus Test, wobei ID=1;
+----+------+-------+---------+
| ID | Name | Geld | Stufe |
+----+------+-------+---------+
| 1 | tom | 100 | 1000|
+----+------+-------+---------+
1 Zeile im Satz (0,00 Sek.)

2.3 Phantomlesen

//2.3 Phantom liest SessionA SessionB
mysql> setze Autocommit=0; mysql> setze Autocommit=0;
Abfrage OK, 0 Zeilen betroffen (0,02 Sek.) Abfrage OK, 0 Zeilen betroffen (0,02 Sek.)
Isolation für Sitzungstransaktionen festlegen Isolationsebene für Sitzungstransaktionen festlegen Nicht festgeschriebenes Lesen;
Leseebene nicht festgeschrieben; Abfrage OK, 0 Zeilen betroffen (0,00 Sek.)
Abfrage OK, 0 Zeilen betroffen (0,00 Sek.)      
mysql> wähle * aus Test; mysql> wähle * aus Test;
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+-------+----------+-----------+              
| ID | Name | Geld | Stufe | | ID | Name | Geld | Stufe |
+----+-------+-------+-------+ +----+-------+----------+----------+
| 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 |
| 2 | Buchse | 200 | 2 | | 2 | Buchse | 200 | 2 |
| 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 |
+----+-------+-------+-------+ +----+-------+----------+----------+
3 Zeilen im Set (0,00 Sek.) 3 Zeilen im Set (0,00 Sek.)
--------------------------------------------------------------------------------
                        mysql> Testsatz aktualisieren, Level=100, wobei ID=1;
                        Abfrage OK, 1 Zeile betroffen (0,00 Sek.)
                        Übereinstimmende Zeilen: 1 Geändert: 1 Warnungen: 0
--------------------------------------------------------------------------------
mysql> Auswahl *aus Test, wobei ID=1;
+----+------+-------+---------+
| ID | Name | Geld | Stufe |
+----+------+-------+---------+
| 1 | tom | 100 | 100 |
+----+------+-------+---------+
1 Zeile im Satz (0,00 Sek.)
--------------------------------------------------------------------------------
                        mysql> in Test einfügen (Name, Geld, Level) VALUES ('tim', 250, 4);
                        Abfrage OK, 1 Zeile betroffen (0,01 Sek.)
--------------------------------------------------------------------------------
//Phantomlesen//Zweimal lesen, beim zweiten Mal sind mehr Daten von Tim vorhanden//Wenn es sich um RR-Ebene handelt, müssen Sie die aktuelle Lesesperre „select * from test“ im Freigabemodus verwenden, andernfalls können Sie Tims Daten wegen MVCC nicht lesenmysql> select * from test;
+----+-------+-------+---------+
| ID | Name | Geld | Stufe |
+----+-------+-------+---------+
| 1 | tom | 100 | 1 |
| 2 | Wagenheber | 200 | 2 |
| 3 | lucas | 300 | 3 |
| 4 | Zeit | 250 | 4 |
+----+-------+-------+---------+
4 Zeilen im Satz (0,00 Sek.)

3 Lückenschloss (Net-Key-Schloss)

MVCC ermöglicht Transaktionen das aktuelle Lesen auf RR-Ebene, um Phantomleseprobleme im Lesefall zu vermeiden. Was ist jedoch beim Schreiben von Aktualisierungen? Was muss ich tun, wenn ich beim Aktualisieren des Bereichs neue Daten in den Bereich einfügen möchte?

Es liegt also eine Lückensperre vor. Beim Aktualisieren der Daten in einem bestimmten Intervall werden alle Datensätze in diesem Intervall gesperrt. Beispielsweise werden durch das Update XXX mit der ID zwischen 1 und 100 alle Datensätze mit IDs zwischen 1 und 100 gesperrt. Es ist zu beachten, dass, wenn in diesem Intervall kein Datensatz vorhanden ist, der Datensatz ebenfalls gesperrt wird. Wenn zu diesem Zeitpunkt eine andere Transaktion Daten zu diesem Intervall hinzufügt, muss sie warten, bis die vorherige Transaktion die Sperrressourcen freigibt.

Die Verwendung von Gap Locks hat zwei Gründe: Zum einen soll Phantomlesen verhindert werden, zum anderen sollen die Anforderungen der Wiederherstellung und Zuweisung erfüllt werden.

3.1 Bereichslückensperre, explizites links offenes und rechts geschlossenes Intervall

//Gap Lock (Net-Key Lock) Bereichslückensperre, links offen rechts geschlossen Intervall SessionA SessionB
mysql> setze Autocommit=0; mysql> setze Autocommit=0;
Abfrage OK, 0 Zeilen betroffen (0,02 Sek.) Abfrage OK, 0 Zeilen betroffen (0,02 Sek.)
     
mysql> wähle * aus Test; mysql> wähle * aus Test;
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+-------+----------+----------+              
| ID | Name | Geld | Stufe | | ID | Name | Geld | Stufe |
+----+-------+-------+-------+ +----+-------+----------+----------+
| 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 |
| 2 | Buchse | 200 | 2 | | 2 | Buchse | 200 | 2 |
| 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 |
+----+-------+-------+-------+ +----+-------+----------+-----------+
3 Zeilen im Set (0,00 Sek.) 3 Zeilen im Set (0,00 Sek.)
--------------------------------------------------------------------------------
mysql> Testsatz-Update-Level=0
wo Geld zwischen 0 und 200 liegt;
Abfrage OK, 2 Zeilen betroffen (0,02 Sek.)
Übereinstimmende Zeilen: 2 Geändert: 2 Warnungen: 0
Theoretisch sollte der Bereich auf [0,300) festgelegt sein.----------------------------------------------------------------
                        Geld einfügen = 0waitmysql> in Test einfügen (Name, Geld, Level) WERTE ('tim', 0,0);
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
                        
                        Geld einfügen = 90waitmysql> in Test einfügen (Name, Geld, Level) WERTE ('tim', 90,0);
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
                        
                        INSERT money=100 WAIT mysql> in Test einfügen (Name, Geld, Level) VALUES ('tim', 100,0);
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
                        
                        INSERT money=299 WAIT mysql> in Test einfügen (Name, Geld, Level) VALUES ('tim', 299,0);
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
                        
                        Geld einwerfen=300 ok
                        mysql> in Test einfügen (Name, Geld, Level) VALUES ('tim', 300,0);
                        Abfrage OK, 1 Zeile betroffen (0,00 Sek.)

3.2 Implizites Intervall mit Einzellückensperre

Im vorherigen Abschnitt wird die Aktualisierung eines bestimmten Bereichs angegeben. Was aber, wenn nur ein Wert aktualisiert wird? Wird es weiterhin Lückenschlösser geben?

//Gap Lock (Net-Key Lock) Einzelnes Gap Lock, links offen rechts geschlossen Intervall SessionA SessionB
mysql> setze Autocommit=0; mysql> setze Autocommit=0;
Abfrage OK, 0 Zeilen betroffen (0,02 Sek.) Abfrage OK, 0 Zeilen betroffen (0,02 Sek.)
     
mysql> wähle * aus Test; mysql> wähle * aus Test;
--------------------------------------------------------------------------------
+----+-------+-------+-------+ +----+-------+----------+----------+              
| ID | Name | Geld | Stufe | | ID | Name | Geld | Stufe |
+----+-------+-------+-------+ +----+-------+----------+-----------+
| 1 | tom | 100 | 1 | | 1 | tom | 100 | 1 |
| 2 | Buchse | 200 | 2 | | 2 | Buchse | 200 | 2 |
| 3 | lucas | 300 | 3 | | 3 | lucas | 300 | 3 |
+----+-------+-------+-------+ +----+-------+----------+----------+
3 Zeilen im Set (0,00 Sek.) 3 Zeilen im Set (0,00 Sek.)
--------------------------------------------------------------------------------
mysql> Testsatz-Update-Level=0
wobei Geld = 200;
Abfrage OK, 1 Zeile betroffen (0,00 Sek.)
Übereinstimmende Zeilen: 1 Geändert: 1 Warnungen: 0
Theoretisch sollte der Bereich auf [0,300) festgelegt sein.----------------------------------------------------------------
                        Geld einzahlen=0 ok
                        mysql> in Test einfügen (Name, Geld, Level) VALUES ('tim',0,0);
                        Abfrage OK, 1 Zeile betroffen (0,00 Sek.)
                        
                        Geld einwerfen=90 ok
                        mysql> in Test einfügen (Name, Geld, Level) VALUES ('tim', 90,0);
                        Abfrage OK, 1 Zeile betroffen (0,00 Sek.)
                        
                        INSERT money=100 WAIT mysql> in Test einfügen (Name, Geld, Level) VALUES ('tim', 100,0);
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
                        
                        INSERT money=150 WAIT mysql> in Test einfügen (Name, Geld, Level) VALUES ('tim', 150,0);
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
                        
                        INSERT money=200 WAITmysql> in Test einfügen (Name, Geld, Level) VALUES ('tim', 200,0);
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
                        
                        INSERT money=240 WAIT mysql> in Test einfügen (Name, Geld, Level) VALUES ('tim', 240,0);
                        FEHLER 1205 (HY000): Wartezeit für Sperre überschritten;
                        Versuchen Sie, die Transaktion neu zu starten
                        
                        Geld einwerfen=300 ok
                        mysql> in Test einfügen (Name, Geld, Level) VALUES ('tim', 300,0);
                        Abfrage OK, 1 Zeile betroffen (0,00 Sek.)

Wenn das Intervall nicht angegeben ist, ist das implizite Intervall das Intervall, das durch die Werte der beiden Knoten vor und nach dem Index B+Nummer bestimmt wird, das ebenfalls links offen und rechts geschlossen ist. Für das obige Beispiel ist es das Intervall [0,300).

Zusammenfassen

Dies ist das Ende dieses Artikels über den MySQL InnoDB-Sperrmechanismus. Weitere Informationen zum MySQL InnoDB-Sperrmechanismus finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • Zusammenfassung der MySQL InnoDB-Architektur
  • Eine kurze Einführung in MySQL InnoDB ReplicaSet
  • Detaillierte Erläuterung der Speicherverwaltung der MySQL InnoDB-Speicher-Engine
  • Hauptfunktionen von MySQL Innodb: Einfügepuffer
  • Zusammenfassung der MySQL InnoDB-Sperren
  • So unterscheiden Sie MySQLs innodb_flush_log_at_trx_commit und sync_binlog
  • Ausführliche Erläuterung der InnoDB-Sperren in der MySQL-Technologie
  • Ändern Sie die MySQL-Datenbank-Engine in InnoDB
  • Beschreiben Sie kurz die MySQL InnoDB-Speicher-Engine
  • Ausführliche Erläuterung zum Beispiel der MySQL InnoDB-Tablespace-Verschlüsselung
  • MySQL InnoDB-Quellcodeanalyse für Transaktionssperren

<<:  Beim Zugriff auf die Homepage eines im Docker-Modus gestarteten Tomcat tritt ein 404-Fehler auf

>>:  Zusammenfassung des Front-End-Wissens im Gokudō-Spiel

Artikel empfehlen

js zur Implementierung eines Web-Rechners

Wie erstelle ich mit HTML, CSS und JS einen einfa...

Teilen Sie einige ungewöhnliche, aber nützliche JS-Techniken

Vorwort Programmiersprachen enthalten normalerwei...

Faint: „Nutzen Sie Web 2.0, um standardkonforme Seiten zu erstellen“

Heute sprach jemand mit mir über ein Website-Entw...

Verwenden Sie Docker, um ein Git-Image mithilfe des Klon-Repositorys zu erstellen

Überblick Ich verwende Docker seit über einem Jah...

Detailliertes Beispiel für die Verkettung mehrerer Felder in MySQL

Das Zusammenführen von Zeilen- und Feldergebnisse...

Implementierungscode für unendliches Scrollen mit n Containerelementen

Szenario So rendern Sie Listen mit bis zu 10.000 ...

Beispiel für die Verwendung einer Keep-Alive-Komponente in Vue

Problembeschreibung (was ist Keep-Alive) Keep-Ali...

Eine kurze Diskussion über die Definition und Vorsichtsmaßnahmen von H-Tags

Den Ergebnissen zufolge gibt es für die Definitio...

Unterschied zwischen den Methoden querySelector und getElementById in JS

Inhaltsverzeichnis 1. Übersicht 1.1 Verwendung vo...

So verwenden Sie async und await in JS

Inhaltsverzeichnis 1. asynchron 2. warten: 3. Umf...

So implementieren Sie die Ein-Klick-Bereitstellung von NFS unter Linux

Serverinformationen Verwaltungsserver: m01 172.16...

So implementieren Sie Dual-Machine-Master und Backup mit Nginx+Keepalived

Vorwort Lassen Sie mich zunächst Keepalived vorst...

JavaScript zum Erzielen eines Skin-Effekts (Ändern des Hintergrunds)

In diesem Artikel wird der spezifische JavaScript...