Warum Entwickler Datenbanksperren im Detail verstehen müssen

Warum Entwickler Datenbanksperren im Detail verstehen müssen

1.Sperren?

1.1 Was ist ein Schloss?

Die eigentliche Bedeutung eines Schlosses ist: ein verschlossener Gegenstand, der mit einem Schlüssel oder Code geöffnet werden kann. Sperren in Computern werden im Allgemeinen verwendet, um den gleichzeitigen Zugriff auf gemeinsam genutzte Ressourcen zu verwalten. Lock und synchronisiert, die unseren Java-Klassenkameraden bekannt sind, sind beispielsweise allgemeine Sperren. Natürlich gibt es in unserer Datenbank auch Sperren, um den gleichzeitigen Zugriff auf Ressourcen zu steuern. Dies ist einer der Unterschiede zwischen Datenbanken und Dateisystemen.

1.2 Warum müssen Sie Datenbanksperren verstehen?

Generell gilt, dass allgemeine Entwickler bei der Verwendung der Datenbank über ausreichende Kenntnisse in DQL (Auswählen) und DML (Einfügen, Aktualisieren, Löschen) verfügen.

Xiao Ming ist ein Java-Entwicklungsingenieur, der gerade seinen Abschluss gemacht hat und in einem Internetunternehmen arbeitet. Seine übliche Aufgabe besteht darin, die Anforderungen des PM zu erfüllen. Natürlich kann er beim Erfüllen der Anforderungen nicht auf das Framework von Spring, SpringMVC und Mybatis verzichten. Im Allgemeinen schreibt er das SQL also immer noch von Hand. Wenn er auf ein komplizierteres SQL stößt, sucht er im Internet bei Baidu. Für einige wichtige Vorgänge, z. B. Transaktionen, verwendet Xiao Ming Spring-Transaktionen, um Datenbanktransaktionen zu verwalten. Aufgrund der geringen Datenmenge sind derzeit keine verteilten Transaktionen beteiligt.

Xiao Ming hatte in den letzten Monaten ein ruhiges Leben. Bis er eines Tages eine Anfrage erhielt. Der Händler hatte ein Konfigurationselement namens Rabattkonfigurationselement, mit dem er „Kaufe eins, bekomme eins gratis“, „Kaufe eins, bekomme zwei gratis“ und andere Regeln konfigurieren konnte. Natürlich wurden diese Konfigurationen stapelweise an das Backend übertragen. Dies stellte ein Problem dar, da jede Regel abgeglichen werden musste, um festzustellen, ob sie gelöscht, hinzugefügt oder geändert wurde. Dies machte die Backend-Logik komplizierter. Der schlaue Xiao Ming dachte sich eine Möglichkeit aus, die Konfiguration des Händlers direkt zu löschen und sie dann alle hinzuzufügen. Xiao Ming schloss die Entwicklung sofort ab und brachte sie erfolgreich auf den Markt.

Beim ersten Start war alles in Ordnung, in den Protokollen traten jedoch häufig MySQL-Insert-Deadlock-Ausnahmen auf. Da Xiao Ming wenig Erfahrung hatte und zum ersten Mal auf dieses Problem stieß, fragte er den Veteranen in seiner Gruppe, Dahong. Als Dahong dieses Problem sah und sich seinen Code ansah, gab er einige Befehle aus, las einige Protokolle und fand das Problem sofort. Er sagte Xiao Ming: Dies liegt daran, dass beim Löschen eine Lückensperre hinzugefügt wird, Lückensperren jedoch miteinander kompatibel sind. Beim Einfügen neuer Daten wird jedoch die Sperre für die Einfügungsabsicht durch die Lückensperre blockiert, was zu einer gegenseitigen Belegung der Ressourcen auf beiden Seiten führt und zu einem Deadlock führt. Nachdem er das gehört hatte, schien Xiao Ming es zu verstehen, aber da Dahong viel zu tun hatte, war es unbequem, sie die ganze Zeit zu stören, also beschloss er, selbst darüber nachzudenken. Nach Feierabend dachte Xiao Ming über Dahongs Worte nach: Was ist eine Lückensperre und was ist eine Einfügesperre? Es scheint, dass Sie als Entwickler nicht nur SQL für die Datenbank schreiben können müssen, da Sie sonst einige schwierige Probleme nicht lösen können. Nachdem Xiao Ming darüber nachgedacht hatte, begab er sich auf den Weg ohne Wiederkehr, um die MySQL-Sperre zu erlernen.

2. InnoDB

2.1MySQL-Architektur

Xiao Ming hatte es nicht eilig, dieses Wissen freizugeben. Er lernte zuerst die MySQL-Architektur kennen:

Es lässt sich feststellen, dass Mysql aus Verbindungspoolkomponenten, Verwaltungsdiensten und Toolkomponenten, SQL-Schnittstellenkomponenten, Abfrageanalysekomponenten, Optimierungskomponenten, Pufferkomponenten, einer Plug-in-Speicher-Engine und physischen Dateien besteht.

Xiao Ming entdeckte, dass die Speicher-Engine in MySQL in Form eines Plug-Ins bereitgestellt wird. In MySQL gibt es mehrere Speicher-Engines, und jede Speicher-Engine hat ihre eigenen Eigenschaften. Dann gab Xiao Ming in die Befehlszeile ein:

Motoren anzeigen \G;

Es stellt sich heraus, dass es sehr viele Arten von Motoren gibt.

Geben Sie dann den folgenden Befehl ein, um die aktuelle Standard-Datenbank-Engine anzuzeigen:

Variablen wie „%storage_engine%“ anzeigen; 

Xiao Ming bemerkte plötzlich, dass seine Datenbank InnoDB verwendete. Er erinnerte sich vage daran, dass er in der Schule von einer Engine namens MyISAM gehört hatte. Xiao Ming fragte sich, was der Unterschied zwischen den beiden war. Er suchte sofort einige Informationen heraus:

Vergleichsartikel InnoDB MeinIsAM
Transaktionen Unterstützung Wird nicht unterstützt
Sperren Unterstützt MVCC-Zeilensperren Tabellensperre
Fremdschlüssel Unterstützung Wird nicht unterstützt
Stauraum Der Speicherplatz ist aufgrund der Notwendigkeit eines Hochgeschwindigkeits-Caching groß Komprimierbar
Anwendbare Szenarien Es gibt eine gewisse Menge an Update und Insert Viele Optionen

Xiao Ming verstand den Unterschied zwischen InnoDB und MyISAM ungefähr. Da er InnoDB verwendete, machte sich Xiao Ming darüber keine allzu großen Gedanken.

2.2 Transaktionsisolierung

Bevor Xiao Ming das Thema Sperren studierte, erinnerte er sich an die Transaktionsisolierung von Datenbanken, die er in der Schule gelernt hatte. Tatsächlich besteht eine der Funktionen von Sperren in der Datenbank darin, eine Transaktionsisolierung zu erreichen. Die Isolierung von Transaktionen wird tatsächlich verwendet, um Probleme wie Dirty Reads, nicht wiederholbare Reads und Phantom Reads zu lösen.

2.2.1 Schmutziges Lesen

Eine Transaktion liest aktualisierte Daten, die nicht von einer anderen Transaktion festgeschrieben wurden. Was bedeutet das?

Zeit Transaktion A Transaktion B
1 beginnen;
2 Wählen Sie * vom Benutzer, wobei ID = 1; beginnen;
3
Benutzersatz aktualisieren, namm = „Test“, wobei ID = 1;
4 Wählen Sie * vom Benutzer, wobei ID = 1;
5 begehen; begehen;

Bei den Transaktionen A und B hat Transaktion A die Daten mit der ID 1 in der Benutzertabelle zu den Zeitpunkten 2 und 4 abgefragt, Transaktion B hat sie jedoch zum Zeitpunkt 3 geändert, sodass das Abfrageergebnis von Transaktion A in 4 tatsächlich das von Transaktion B geänderte Ergebnis war. Dadurch wird die Isolation in der Datenbank aufgehoben.

2.2.2 Nicht wiederholbares Lesen

Das mehrmalige Lesen derselben Daten in derselben Transaktion kann zu unterschiedlichen Ergebnissen führen. Im Gegensatz zu Dirty Reads handelt es sich bei den hier gelesenen Daten um die festgeschriebenen Daten.

Zeit Transaktion A Transaktion B
1 beginnen;
2 Wählen Sie * vom Benutzer, wobei ID = 1; beginnen;
3
Benutzersatz aktualisieren, namm = „Test“, wobei ID = 1;
4
begehen;
5 Wählen Sie * vom Benutzer, wobei ID = 1;
6 begehen;
Die in Transaktion B übermittelte Operation erfolgt vor der zweiten Abfrage von Transaktion A, das Aktualisierungsergebnis von Transaktion B wird jedoch immer noch gelesen, wodurch auch die Isolation der Transaktion zerstört wird.

Die in Transaktion B übermittelte Operation erfolgt vor der zweiten Abfrage von Transaktion A, das Aktualisierungsergebnis von Transaktion B wird jedoch immer noch gelesen, wodurch auch die Isolation der Transaktion zerstört wird.

2.2.3 Phantom-Lesevorgänge

Eine Transaktion liest die Einfügedaten, die von einer anderen Transaktion festgeschrieben wurden.

Zeit Transaktion A Transaktion B
1 beginnen;
2 Wählen Sie * vom Benutzer, bei dem die ID > 1 ist; beginnen;
3
Benutzerauswahl 2 einfügen;
4
begehen;
5 Wählen Sie * vom Benutzer, bei dem die ID > 1 ist;
6 begehen;

In Transaktion A wurden zwei Abfragen für IDs größer als 1 durchgeführt. In der ersten Abfrage waren keine Daten im Ergebnis enthalten. Da Transaktion B jedoch Daten mit ID=2 eingefügt hat, konnte Transaktion A in der zweiten Abfrage die in Transaktion B eingefügten Daten finden.

Isolation bei Transaktionen:

Isolationsstufe Schmutzige Lektüre Nicht wiederholbares Lesen Phantom lesen
Nicht festgeschriebenes Lesen (RUC) NEIN NEIN NEIN
Lesen bestätigt (RC) JA NEIN NEIN
Wiederholbares Lesen (RR) JA JA NEIN
Serialisierbar JA JA JA

Xiao Ming bemerkte beim Sammeln von Informationen, dass InnoDB sich ein wenig von anderen Datenbanken unterscheidet. Das wiederholbare Lesen von InnoDB kann tatsächlich Phantom-Lesevorgänge lösen. Xiao Ming dachte: Dieses InnoDB ist ziemlich großartig. Ich muss mir genauer ansehen, wie es funktioniert.

2.3 InnoDB-Sperrtypen

Xiao Ming versteht zunächst die gängigen Sperrtypen in MySQL:

2.3.1 S oder X

In InnoDb sind zwei Standardsperren auf Zeilenebene implementiert, die man sich einfach als zwei Lese-/Schreibsperren vorstellen kann:

  • S-Shared Lock: auch Lesesperre genannt. Andere Transaktionen können weiterhin Shared Locks hinzufügen, aber keine exklusiven Locks.
  • X-exklusive Sperre: auch Schreibsperre genannt. Sobald eine Schreibsperre hinzugefügt wurde, kann sie von anderen Transaktionen nicht mehr gesperrt werden.

Kompatibilität: Dies bedeutet, dass Transaktion B versucht, eine bestimmte Sperre für eine bestimmte Zeile zu erhalten, nachdem Transaktion A eine bestimmte Sperre für eine bestimmte Zeile erhalten hat. Wenn dies sofort möglich ist, spricht man von Sperrkompatibilität, andernfalls von einem Konflikt.

Die vertikale Achse stellt die vorhandenen Sperren dar und die horizontale Achse die Sperren, die erworben werden sollen.

. X S
X Konflikt Konflikt
S Konflikt kompatibel

2.3.2 Absichtssperre

Intention Locks sind Sperren auf Tabellenebene in InnoDB. Wie der Name schon sagt, werden sie verwendet, um auszudrücken, was eine Transaktion erreichen möchte. Absichtssperren werden unterteilt in:

  • Absichtliche gemeinsame Sperre: drückt aus, dass eine Transaktion gemeinsame Sperren für bestimmte Zeilen einer Tabelle erhalten möchte.
  • Absichtliche exklusive Sperre: drückt aus, dass eine Transaktion exklusive Sperren für bestimmte Zeilen einer Tabelle erhalten möchte.

Wozu dient dieses Schloss? Wozu brauchen Sie dieses Schloss? Wenn es keine solche Sperre gibt und Sie dieser Tabelle eine Tabellensperre hinzufügen möchten, besteht die allgemeine Vorgehensweise darin, jede Zeile zu durchsuchen, um festzustellen, ob eine Zeilensperre vorhanden ist. Dies ist zu ineffizient. Wenn wir jedoch eine absichtliche Sperre haben, müssen wir nur feststellen, ob eine absichtliche Sperre vorhanden ist, und müssen nicht jede Zeile einzeln scannen.

InnoDB unterstützt Sperren auf Zeilenebene, daher kann die Kompatibilität von InnoDB-Sperren wie folgt erweitert werden:

. IX IST X S
IX kompatibel kompatibel Konflikt Konflikt
IST kompatibel kompatibel Konflikt kompatibel
X Konflikt Konflikt Konflikt Konflikt
S Konflikt kompatibel Konflikt kompatibel

2.3.3 Auto-Inkrement-Sperre

Die Auto-Increment-Sperre ist ein spezieller Tabellensperrmechanismus, der die Leistung bei gleichzeitigen Einfügevorgängen verbessert. Dieses Schloss verfügt über mehrere Funktionen:

  • Die Sperre wird aufgehoben, wenn SQL ausgeführt wird, nicht, wenn die Transaktion ausgeführt wird.
  • Bei „Einfügen...Auswählen“ wirkt sich das Einfügen großer Datenmengen auf die Einfügeleistung aus, weil dadurch die Ausführung einer anderen Transaktion blockiert wird.
  • Der Auto-Inkrement-Algorithmus ist konfigurierbar.

Nach MySQL Version 5.1.2 gibt es viele Optimierungen und die Art und Weise zum Erhöhen der Sperre kann je nach Modus angepasst werden. Xiao Ming sah dies und öffnete sein MySQL. Er stellte fest, dass es sich um Version 5.7 handelte. Daher gab er die folgende Anweisung ein, um den aktuellen Sperrmodus abzurufen:

mysql> Variablen wie „innodb_autoinc_lock_mode“ anzeigen;

+--------------------------+----------+

| Variablenname | Wert |

+--------------------------+----------+

| innodb_autoinc_lock_mode | 2 |

+--------------------------+----------+

1 Zeile im Satz (0,01 Sek.)

In MySQL hat innodbautoinclock_mode drei Konfigurationsmodi: 0, 1 und 2, die jeweils dem „traditionellen Modus“, „kontinuierlichen Modus“ und „verschachtelten Modus“ entsprechen.

  • Traditioneller Modus: Dies ist die Tabellensperre, die wir oben verwenden.
  • Kontinuierlicher Modus: Verwenden Sie Mutexe, wenn die Anzahl der Zeilen während des Einfügens bestimmt werden kann, und verwenden Sie Tabellensperren, wenn die Anzahl der Zeilen nicht bestimmt werden kann.
  • Interleaved-Modus: Alle verwenden Mutexe. Warum heißt er Interleaved-Modus? Es ist möglich, dass die Autoinkrementwerte während der Batch-Einfügung nicht kontinuierlich sind. Wenn Sie die Kontinuität der Autoinkrementwerte nicht schätzen, wählen Sie im Allgemeinen diesen Modus, der die beste Leistung bietet.

2.4InnoDB-Sperralgorithmus

Xiao Ming hat die Arten von Sperren in InnoDB kennengelernt, aber wie diese Sperren verwendet werden, hängt immer noch vom Sperralgorithmus ab.

2.4.1 Aufnahmesperre

Die Datensatzsperre sperrt den Datensatz. Dabei ist zu erklären, dass hier der Indexdatensatz gesperrt wird und nicht unser eigentlicher Datensatz.

  • Wenn der Nicht-Primärschlüsselindex gesperrt ist, wird zunächst der eigene Index gesperrt und anschließend der Primärschlüssel.
  • Wenn für die Tabelle kein Index vorhanden ist (und daher kein Primärschlüssel), wird der versteckte Primärschlüsselindex zum Sperren verwendet.
  • Wenn die zu sperrende Spalte keinen Index hat, werden alle Datensätze in der Tabelle gesperrt.

2.4.2 Lückensperre

Wie der Name schon sagt, sperren Lückensperren die Lücken, nicht jedoch die Datensätze. Das Sperren der Lücke bedeutet, einen bestimmten Bereich zu sperren. Die Lückensperre wird auch als Lückensperre bezeichnet. Sie blockiert keine anderen Lückensperren, blockiert jedoch das Einfügen der Lückensperre. Dies ist auch der Schlüssel zum Verhindern von Phantom-Lesevorgängen.

2.4.3 Nächste-Tasten-Sperre

Diese Sperre ist im Wesentlichen eine Datensatzsperre plus eine Lückensperre. Auf der RR-Isolationsebene (InnoDB-Standard) verwendet InnoDB diesen Algorithmus für Zeilenscansperren. Wenn der Abfragescan jedoch einen eindeutigen Index enthält, werden nur noch Datensatzsperren verwendet. Warum? Weil der eindeutige Index die Anzahl der Zeilen bestimmen kann, während andere Indizes die Anzahl der Zeilen nicht bestimmen können. Es ist möglich, dass die Daten dieses Indexes in anderen Transaktionen erneut hinzugefügt werden, was zu Phantom-Lesevorgängen führt.

Dies erklärt auch, warum MySQL Phantom-Lesevorgänge auf RR-Ebene lösen kann.

2.4.4 Absichtssperre einfügen

Offizielle Erklärung zum Einfügen der Absichtssperre in MySQL:

Eine Einfügeabsichtssperre ist eine Art Lückensperre, die durch INSERT-Operationen vor dem Einfügen einer Zeile gesetzt wird. Diese Sperre signalisiert die Einfügeabsicht so, dass mehrere Transaktionen, die in dieselbe Indexlücke einfügen, nicht aufeinander warten müssen, wenn sie nicht an derselben Position innerhalb der Lücke einfügen. Angenommen, es gibt Indexdatensätze mit den Werten 4 und 7. Separate Transaktionen, die versuchen, Werte von 5 bzw. 6 einzufügen, sperren jeweils die Lücke zwischen 4 und 7 mit Einfügeabsichtssperren, bevor sie die exklusive Sperre für die eingefügte Zeile erhalten, blockieren sich jedoch nicht gegenseitig, da die Zeilen nicht in Konflikt stehen.

Es ist ersichtlich, dass die Einfügeabsichtssperre während des Einfügens generiert wird. Wenn mehrere Transaktionen gleichzeitig unterschiedliche Daten in dieselbe Indexlücke schreiben, muss nicht auf den Abschluss anderer Transaktionen gewartet werden, und es tritt keine Wartezeit für die Sperre auf. Angenommen, es gibt einen Datensatzindex mit den Schlüsselwerten 4 und 7 und verschiedene Transaktionen fügen jeweils 5 und 6 ein. Jede Transaktion generiert eine Einfügeabsichtssperre, die zwischen 4 und 7 hinzugefügt wird, und erhält eine exklusive Sperre für die eingefügte Zeile. Sie werden jedoch nicht gegenseitig gesperrt, da die Datenzeilen nicht in Konflikt stehen.

Hierbei ist zu beachten, dass bei einer Lückensperre das Einfügen der Absichtssperre blockiert wird.

2.5 MVCC

MVCC, Technologie zur Steuerung paralleler Mehrfachversionen. In InnoDB werden nach jeder Datensatzzeile zwei versteckte Spalten hinzugefügt, um die Erstellungsversionsnummer und die Löschversionsnummer aufzuzeichnen. Durch Versionsnummern und Zeilensperren wird die Parallelitätsleistung des Datenbanksystems verbessert.

In MVCC können Lesevorgänge in zwei Typen unterteilt werden:

  • Snapshot-Lesen: Liest historische Daten, einfache Auswahlanweisungen, keine Sperren, MVCC zum Erreichen wiederholbaren Lesens, verwendet den MVCC-Mechanismus zum Lesen der festgeschriebenen Daten beim Rückgängigmachen. Das Lesen erfolgt also blockierungsfrei.
  • Aktueller Lesevorgang: Anweisungen, die eine Sperre erfordern, wie etwa Aktualisieren, Einfügen, Löschen, Auswählen... zum Aktualisieren usw., sind alle aktuelle Lesevorgänge.

Beim Lesen von Snapshots auf der Isolationsebene RR ist der Erstellungszeitpunkt des Snapshots nicht der Zeitpunkt, zu dem die Transaktion gestartet wird, sondern der Zeitpunkt, zu dem die erste Select-Anweisung als Erstellungszeitpunkt des Snapshots verwendet wird. Bei nachfolgenden Auswahlvorgängen wird der Snapshot-Wert zum aktuellen Zeitpunkt gelesen.

Auf der RC-Isolationsebene wird bei jedem Snapshot-Lesevorgang ein neuer Snapshot erstellt.

Das konkrete Prinzip besteht darin, dass jede Zeile zwei ausgeblendete Felder hat, eines zum Aufzeichnen der aktuellen Transaktion und das andere zum Aufzeichnen des Rollbacks, das auf Undolog verweist. Der vorherige Snapshot kann mithilfe von Undolog gelesen werden, ohne dass Speicherplatz für die Aufzeichnung zugewiesen werden muss.

3. Sperranalyse

Xiao Ming hat sich viel Grundwissen über MySQL-Sperren angeeignet und beschloss daher, eine Tabelle zu erstellen, um ein Experiment durchzuführen. Erstellen Sie zunächst eine einfache Benutzertabelle:

CREATE TABLE `Benutzer` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`name` varchar(11) ZEICHENSATZ utf8mb4 STANDARD NULL,

`Kommentar` varchar(11) ZEICHENSATZ utf8 STANDARD NULL,

Primärschlüssel (`id`),

SCHLÜSSEL `index_name` (`name`)

) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

Anschließend wurden mehrere experimentelle Daten eingefügt:

Benutzerauswahl 20.333.333 einfügen;

Benutzerauswahl 25.555.555 einfügen;

Benutzerauswahl 20.999.999 einfügen;

Datenbanktransaktionsisolierung wählt RR aus

3.1 Versuch 1

Xiao Ming startete zwei Transaktionen und führte Experiment 1 durch.

Zeit Transaktion A Transaktion B
1 beginnen;
2 Wählen Sie * vom Benutzer, wobei Name = „555“ für Aktualisierung ist; beginnen;
3
Benutzerauswahl 31,'556','556' einfügen;
4
FEHLER 1205 (HY000): Wartezeit für Sperre überschritten; versuchen Sie, die Transaktion neu zu starten.

Xiao Ming startete zwei Transaktionen und gab die obigen Anweisungen ein. Dabei stellte er fest, dass die Zeit für Transaktion B tatsächlich abgelaufen war. Xiao Ming überprüfte dies und stellte fest, dass er die Zeile mit dem Namen = 555 eindeutig gesperrt hatte. Warum wurde ich also blockiert, als ich den Namen = 556 einfügen wollte? Also öffnete Xiao Ming die Befehlszeile und gab ein:

Wählen Sie * aus information_schema.INNODB_LOCKS

Es wurde festgestellt, dass in Transaktion A eine Next-Key-Sperre zu 555 hinzugefügt wird. Wenn Transaktion B einfügt, wird zuerst die Sperre mit der Einfügeabsicht eingefügt, sodass die folgende Schlussfolgerung gezogen wird:

Es ist ersichtlich, dass Transaktion B aufgrund des Konflikts zwischen der Lückensperre und der Einfügeabsichtssperre blockiert ist.

3.2 Versuch 2

Xiao Ming stellte fest, dass die obige Abfragebedingung einen normalen nicht eindeutigen Index verwendete, also versuchte Xiao Ming es mit dem Primärschlüsselindex:

Zeit Transaktion A Transaktion B
1 beginnen;
2 Wählen Sie * vom Benutzer mit ID = 25 für Aktualisierung; beginnen;
3
Benutzerauswahl 26,'666','666' einfügen;
4
Abfrage OK, 1 Zeile betroffen (0,00 Sek.)
Datensätze: 1 Duplikate: 0 Warnungen: 0

Es wird festgestellt, dass Transaktion B nicht blockiert ist. Was ist los? Xiao Ming ist etwas verwirrt. Gemäß der Routine von Experiment 1 sollte sie blockiert werden, da zwischen 25 und 30 eine Lückensperre vorhanden sein wird. Also verwendete Xiao Ming die Befehlszeile erneut und stellte fest, dass nur die X-Datensatzsperre hinzugefügt wurde. Es stellt sich heraus, dass der eindeutige Index die Datensatzsperre herabstuft. Der Grund dafür ist: Da der nicht eindeutige Index plus die Next-Key-Sperre die genaue Anzahl der Zeilen nicht bestimmen können, ist es möglich, dass andere Transaktionen während Ihrer Abfrage die Daten dieses Indexes erneut hinzufügen, was zur Zerstörung der Isolation führt, was ein Phantomlesen ist. Da der eindeutige Index die einzige Datenzeile angibt, müssen zum Auflösen von Phantomlesevorgängen keine Lückensperren hinzugefügt werden.

3.3 Versuch 3

Der Primärschlüsselindex und der nicht eindeutige Index wurden oben getestet. Es gibt ein weiteres Feld, das keinen Index hat. Was passiert, wenn es gesperrt ist?

Zeit Transaktion A Transaktion B
1 beginnen;
2 Wählen Sie * vom Benutzer, wobei Kommentar = „555“ für Update ist; beginnen;
3
Benutzerauswahl 26,'666','666' einfügen;
4
FEHLER 1205 (HY000): Wartezeit für Sperre überschritten; versuchen Sie, die Transaktion neu zu starten.
5
Benutzerauswahl 31,'3131','3131' einfügen;
6
FEHLER 1205 (HY000): Wartezeit für Sperre überschritten; versuchen Sie, die Transaktion neu zu starten.
7
Benutzerauswahl 10,'100','100' einfügen;
8
FEHLER 1205 (HY000): Wartezeit für Sperre überschritten; versuchen Sie, die Transaktion neu zu starten.
Als Xiao Ming das sah, war er schockiert. Was ist los? Egal, ob er die Daten im Nicht-Gap-Lock-Bereich von Experiment 1 oder die Daten im Gap-Lock verwendete, es funktionierte nicht. Wurde eine Tabellensperre hinzugefügt?

Wenn Sie nicht indizierte Daten verwenden, werden allen gruppierten Indizes tatsächlich Next-Key-Sperren hinzugefügt.

Wenn Sie also bei einer normalen Entwicklung keinen Index für die Abfragebedingungen haben, müssen Sie einen konsistenten Lesevorgang durchführen, d. h. einen gesperrten Lesevorgang. Dadurch wird der gesamten Tabelle ein Index hinzugefügt, wodurch alle anderen Transaktionen blockiert werden und die Datenbank grundsätzlich in einen nicht verfügbaren Zustand versetzt wird.

4. Zurück zum Unfall

4.1 Deadlock

Nachdem Xiao Ming das Experiment beendet hatte, verstand er endlich einige grundlegende Sperrroutinen, aber was war der Deadlock, der zuvor online aufgetreten war?

Deadlock: bezeichnet ein Phänomen, bei dem zwei oder mehr Transaktionen aufgrund von Konkurrenz um Ressourcen während der Ausführung aufeinander warten. Dies bedeutet, dass Deadlocks nur dann auftreten, wenn es Wartezeiten gibt. Deadlocks können durch die Beseitigung der Wartezeiten, z. B. durch ein Rollback der Transaktion, gelöst werden.

Es gibt zwei Möglichkeiten, einen Deadlock zu beheben:

  • Wartezeitüberschreitung: Wenn eine Transaktion nach Ablauf einer Wartezeit zurückgesetzt wird, kann eine andere Transaktion ausgeführt werden. Dies ist jedoch ineffizient und führt zu Wartezeiten. Ein weiteres Problem besteht darin, dass eine Transaktion mit hohem Gewicht und vielen aktualisierten Daten, die zurückgesetzt wird, zu einer Verschwendung von Ressourcen führt.
  • Warte-auf-Graph: Der Warte-auf-Graph wird verwendet, um die Wartebeziehung zwischen Transaktionen zu beschreiben. Wenn in diesem Graphen eine Schleife auftritt, sieht diese wie folgt aus:

Wenn ein Rollback auftritt, wählt InnoDB normalerweise das Rollback von Transaktionen mit kleineren Gewichten, d. h. Transaktionen mit kleineren Undo-Werten.

4.2 Online-Probleme

Xiao Ming verfügt über alle erforderlichen Grundkenntnisse und beginnt, dieses Problem in seiner lokalen Tabelle zu reproduzieren:

Zeit Transaktion A Transaktion B
1 beginnen; beginnen;
2 Löschen vom Benutzer, bei dem Name = „777“; Löschen vom Benutzer, bei dem Name = „666“;
3 Benutzerauswahl 27,'777','777' einfügen; Benutzerauswahl 26,'666','666' einfügen;
4 FEHLER 1213 (40001): Beim Versuch, eine Sperre zu erhalten, wurde ein Deadlock festgestellt. Versuchen Sie, die Transaktion neu zu starten. Abfrage OK, 1 Zeile betroffen (14,32 Sek.) Datensätze: 1 Duplikate: 0 Warnungen: 0

Sie können sehen, dass Transaktion A zurückgesetzt wird, während Transaktion B erfolgreich ausgeführt wird. Was ist zu jedem Zeitpunkt passiert?

Zeitpunkt 2: Transaktion A löscht die Daten mit dem Namen = „777“. Sie muss dem Index 777 eine Next-Key-Sperre hinzufügen, die jedoch nicht existiert. Daher wird nur eine Lückensperre zwischen 555 und 999 hinzugefügt. In ähnlicher Weise fügt Transaktion B auch eine Lückensperre zwischen 555 und 999 hinzu. Spaltschlösser sind untereinander kompatibel.

Zeitpunkt 3: Transaktion A führt einen Einfügevorgang aus und fügt zuerst eine Absichtssperre ein. Es gibt jedoch eine Lückensperre zwischen 555 und 999. Aufgrund des Konflikts zwischen der Einfügeabsichtssperre und der Lückensperre wird Transaktion A blockiert und wartet darauf, dass Transaktion B die Lückensperre freigibt. Transaktion B ist ähnlich und wartet darauf, dass Transaktion A die Lückensperre freigibt. Es wartet also eine A->B, B->A-Schleife.

Zeitpunkt 4: Der Transaktionsmanager entscheidet sich für ein Rollback der Transaktion A und der Einfügevorgang der Transaktion B wird erfolgreich ausgeführt.

4.3 Fehlerbehebungen

Xiao Ming hat dieses Problem schließlich gefunden, das auf die Lückensperre zurückzuführen ist. Jetzt müssen wir dieses Problem lösen. Der Grund für dieses Problem ist die Lückensperre, also lasst uns sie beseitigen:

  • Lösung 1: Reduzieren Sie die Isolationsebene auf RC. Auf der RC-Ebene werden keine Lückensperren hinzugefügt, sodass es keine Probleme gibt. Auf der RC-Ebene treten jedoch Phantom-Lesevorgänge auf, und festgeschriebene Lesevorgänge zerstören das Isolationsproblem. Daher ist diese Lösung nicht durchführbar.
  • Lösung 2: Die Isolationsebene wird auf serialisierbar aktualisiert. Nach dem Testen stellte Xiao Ming fest, dass dieses Problem nicht auftreten würde. Auf der serialisierbaren Ebene ist die Leistung jedoch geringer und es kommt zu mehr Sperrwartezeiten, was ebenfalls nicht berücksichtigt wird.
  • Lösung drei: Ändern Sie die Codelogik. Löschen Sie nicht direkt. Lassen Sie stattdessen die Geschäftslogik bestimmen, welche Daten aktualisiert, gelöscht und hinzugefügt werden. Dieser Arbeitsaufwand ist etwas groß. Xiao Ming hat diese Logik für direktes Löschen geschrieben, um diese komplizierten Dinge zu vermeiden, daher wird diese Lösung vorerst nicht in Betracht gezogen.
  • Lösung 4: Weniger Änderungen an der Codelogik. Vor dem Löschen können Sie über einen Snapshot abfragen (ohne Sperren). Wenn die Abfrage keine Ergebnisse liefert, fügen Sie direkt ein. Wenn über den Primärschlüssel gelöscht wird, wird im vorherigen Experiment 2 in Abschnitt 3 der eindeutige Index auf eine Datensatzsperre herabgestuft, sodass keine Lückensperre vorhanden ist.

Nach einiger Überlegung entschied sich Xiao Ming für die vierte Option, ließ sofort eine Reparatur durchführen und ging dann zur Beobachtung und Überprüfung online. Er stellte fest, dass der Fehler nicht mehr auftrat. Jetzt kann Xiao Ming endlich gut schlafen.

4.4 So verhindern Sie Deadlocks

Durch grundlegendes Lernen und tägliche Erfahrung fasste Xiao Ming die folgenden Punkte zusammen:

  • Der Zugriff auf Tabellen und Zeilen erfolgt in einer festgelegten Reihenfolge. Bei Querzugriffen ist die Wahrscheinlichkeit größer, dass es zu Warteschleifen bei Transaktionen kommt.
  • Versuchen Sie, große Transaktionen zu vermeiden. Je mehr Ressourcensperren Sie belegen, desto wahrscheinlicher ist es, dass Deadlocks auftreten. Es empfiehlt sich, die Aufgaben in kleinere Einheiten aufzuteilen.
  • Reduzieren Sie die Isolationsstufe. Wenn das Geschäft dies zulässt (wie in 4.3 oben analysiert, erlauben es einige Geschäfte nicht), ist auch das Herabsetzen der Isolationsstufe eine gute Wahl. Beispielsweise kann das Anpassen der Isolationsstufe von RR auf RC viele durch Lückensperren verursachte Deadlocks vermeiden.
  • Fügen Sie der Tabelle entsprechende Indizes hinzu. Verhindern Sie das Auftreten von Tabellensperren, wenn kein Index vorhanden ist, da sonst die Wahrscheinlichkeit von Deadlocks plötzlich ansteigt.

endlich

Aufgrund des begrenzten Platzes können viele Dinge nicht vollständig vorgestellt werden. Wenn Sie interessiert sind, können Sie Kapitel 6 von „MySQL Technology Insider – InnoDB Engine“ und Master Hes MySQL Lock Processing Analysis lesen. Das Niveau des Autors ist begrenzt. Wenn Fehler vorhanden sind, weisen Sie bitte darauf hin.

Das ist alles für diesen Artikel. Ich hoffe, dass der Inhalt dieses Artikels für Ihr Studium oder Ihre Arbeit von gewissem Referenzwert ist. Vielen Dank für Ihre Unterstützung von 123WORDPRESS.COM.

Das könnte Sie auch interessieren:
  • Detaillierte Einführung in den MySQL-Datenbank-Sperrmechanismus
  • Ursachen und Lösungen für einen Deadlock in der MySQL-Datenbank
  • Ursachen und Lösungen für MySQL-Datenbanksperren
  • Analyse des Deadlock-Prozesses in der MySQL-Datenbank (zum Aktualisieren auswählen)
  • Analyse einer Deadlock-Instanz in einer MySQL-Datenbank
  • Analyse des Purge-Deadlock-Problems in der MySQL-Datenbank

<<:  React+Amap ermittelt Breiten- und Längengrad in Echtzeit und lokalisiert die Adresse

>>:  So installieren und konfigurieren Sie einen FTP-Server in CentOS8.0

Artikel empfehlen

Mehrere Möglichkeiten zum einfachen Durchlaufen von Objekteigenschaften in JS

Inhaltsverzeichnis 1. Selbstaufzählbare Eigenscha...

So richten Sie den PostgreSQL-Start unter Ubuntu 16.04 ein

Da PostgreSQL kompiliert und installiert ist, müs...

Die HTML-Tag-ID kann eine Variable sein

<table id=" <%=var1%>">, der...

So konfigurieren Sie mehrere Projekte mit demselben Domänennamen in Nginx

Es gibt zwei Möglichkeiten, mit Nginx mehrere Pro...

Einführung und Verwendungszusammenfassung der negativen Margenfunktion

Bereits in den CSS2-Empfehlungen von 1998 verschwa...

Verschieben Sie die MySQL-Datenbank unter Windows auf eine andere Festplatte

Vorwort Heute habe ich MySQL installiert und fest...

Einführung in den Prozess zum Erstellen eigener FTP- und SFTP-Server

FTP und SFTP werden häufig als Dateiübertragungsp...

So verhindern Sie das Flashen von Vue in kleinen Projekten

Zusammenfassung HTML: Element plus V-Umhang CSS: ...

Detaillierte Schritte zur Installation von MYSQL8.0 auf CentOS7.6

1. Im Allgemeinen ist MariaDB in CentOS standardm...

Canonical ermöglicht Linux-Desktop-Apps mit Flutter (empfohlen)

Das Ziel von Google mit Flutter bestand immer dar...

Einfaches Anwendungsbeispiel für rekursive MySQL 8.0-Abfragen

Vorwort Dieser Artikel verwendet die neuen Funkti...

14 Möglichkeiten zum Erstellen von Website-Inhalten, die Ihre Besucher fesseln

Wenn ich im Internet surfe, sehe ich oft Websites...