Fun with Mysql Series – Teil 14: Ausführliche Erklärung von Transaktionen

Umgebung: mysql5.7.25, demonstriert im cmd-Befehl.

Während des Entwicklungsprozesses werden häufig Datenbanktransaktionen verwendet, daher ist dieses Kapitel sehr wichtig.

Inhalt dieses Artikels

  1. Was ist eine Transaktion und wofür wird sie verwendet?

  2. Mehrere Merkmale von Transaktionen

  3. Ausführliche Erläuterung gängiger Anweisungen zum Transaktionsvorgang

  4. Detaillierte Erläuterung der Transaktionsisolationsstufe

  5. Detaillierte Erläuterung von Dirty Read, Non-Repeatable Read, Repeatable Read und Phantom Read

  6. Demonstrieren Sie die Phänomene, die durch verschiedene Isolationsstufen entstehen

  7. Bezüglich der Wahl der Isolationsstufe

Was ist eine Transaktion?

Eine Transaktion in einer Datenbank bezieht sich auf die Ausführung einer Reihe von Vorgängen in der Datenbank. Diese Vorgänge werden letztendlich entweder alle erfolgreich sein oder fehlschlagen, und es wird keinen Teilerfolg geben.

Zum Beispiel

Wenn Benutzer A beispielsweise 100 an Benutzer B überweist, läuft der Vorgang wie folgt ab:

1.从A账户扣100
2.给B账户加100

Unterstützt durch Transaktionen gibt es am Ende nur zwei Ergebnisse:

  1. Der Vorgang ist erfolgreich: Konto A verringert sich um 100; Konto B erhöht sich um 100

  2. Vorgang fehlgeschlagen: Weder Konto A noch Konto B haben sich geändert.

Wenn keine Transaktionsunterstützung vorhanden ist, kann ein Fehler auftreten: Konto A wird um 100 reduziert und das System hängt sich auf. Dies führt dazu, dass Konto B nicht 100 hinzufügt und Konto A 100 aus dem Nichts verliert.

Mehrere Merkmale von Transaktionen (ACID)

Atomarität

Der gesamte Prozess einer Transaktion ähnelt einer atomaren Operation. Am Ende sind entweder alle erfolgreich oder alle scheitern. Diese Atomizität lässt sich am Endergebnis erkennen. Vom Endergebnis aus ist dieser Prozess unteilbar.

Konsistenz

Vor Beginn der Transaktion, während der Ausführung und nach der Ausführung sind zu diesen Zeitpunkten, wenn mehrere Personen die Daten des Transaktionsvorgangs beobachten, die von ihnen angezeigten Daten konsistent. Beispielsweise sieht Verbindung A während des Transaktionsvorgangs dann 100 Als B es sich zu diesem Zeitpunkt auch ansah, war es ebenfalls 100. Man kann nicht sagen, dass die Daten, die AB sah, unterschiedlich waren. Die Daten, die sie zu einem bestimmten Zeitpunkt sahen, waren konsistent.

Isolierung

Die Ausführung einer Transaktion kann nicht durch andere Transaktionen beeinträchtigt werden. Das heißt, die innerhalb einer Transaktion verwendeten Vorgänge und Daten sind von anderen gleichzeitigen Transaktionen isoliert und gleichzeitig ausgeführte Transaktionen können sich nicht gegenseitig stören.

Haltbarkeit

Sobald eine Transaktion festgeschrieben ist, sollten ihre Änderungen an den Daten in der Datenbank dauerhaft sein. Wenn die Transaktion festgeschrieben wird, werden die Daten auf der Festplatte gespeichert und die Änderung ist dauerhaft.

Transaktionsoperationen in MySQL

Transaktionen in MySQL sind standardmäßig implizite Transaktionen. Wenn Einfüge-, Aktualisierungs- und Löschvorgänge ausgeführt werden, startet die Datenbank automatisch die Transaktion, schreibt sie fest oder setzt sie zurück.

Ob implizite Transaktionen aktiviert werden, wird autocommitdurch Variablen gesteuert.

Daher werden Transaktionen in implizite Transaktionen und explizite Transaktionen unterteilt .

implizite Transaktion

Transaktionen werden automatisch geöffnet, übermittelt oder zurückgesetzt, z. B. Anweisungen zum Einfügen, Aktualisieren oder Löschen. Das Öffnen, Senden oder Zurücksetzen von Transaktionen wird intern automatisch von MySQL gesteuert.

Überprüfen Sie autocommit, ob für die Variable die automatische Übermittlung aktiviert ist

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set, 1 warning (0.00 sec)

autocommitEIN bedeutet, dass die automatische Übermittlung aktiviert ist.

explizite Transaktion

Transaktionen müssen manuell gestartet, festgeschrieben oder zurückgesetzt werden, was vom Entwickler gesteuert wird.

2 Möglichkeiten, Transaktionen manuell zu steuern:

Weg 1:

Grammatik:

//设置不自动提交事务
set autocommit=0;
//执行事务操作
commit|rollback;

Beispiel 1: Vorgang zum Senden einer Transaktion wie folgt:

mysql> create table test1 (a int);
Query OK, 0 rows affected (0.01 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values(1);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

Beispiel 2: Rollback-Transaktionsvorgang wie folgt:

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values(2);
Query OK, 1 row affected (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

Sie können sehen, dass die oben genannten Daten zurückgesetzt wurden.

Lassen Sie autocommites uns wiederherstellen:

mysql> set autocommit=1;
Query OK, 0 rows affected (0.00 sec)

Weg 2:

Grammatik:

start transaction;//开启事务
//执行事务操作
commit|rollback;

Beispiel 1: Vorgang zum Senden einer Transaktion wie folgt:

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values (2);
Query OK, 1 row affected (0.00 sec)

mysql> insert into test1 values (3);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.00 sec)

Oben wurden zwei Daten erfolgreich eingefügt.

Beispiel 2: Rollback-Transaktionsvorgang wie folgt:

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from test1;
Query OK, 3 rows affected (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.00 sec)

Die Daten , die wir in der obigen Transaktion gelöscht haben, test1zeigen, dass drei Zeilen gelöscht wurden und die Transaktion schließlich zurückgesetzt wurde.

Schlüsselwort savepoint

Wir haben während der Transaktion eine große Anzahl von Vorgängen ausgeführt. Vielleicht möchten wir nur einige Daten zurücksetzen. Wie geht das?

Wir können eine große Anzahl von Vorgängen in mehrere Teile aufteilen und dann einen bestimmten Teil angeben, der zurückgesetzt werden soll. savepoinDies kann erreicht werden mit :

Löschen Sie zunächst test1die Tabellendaten:

mysql> delete from test1;
Query OK, 3 rows affected (0.00 sec)

mysql> select * from test1;
Empty set (0.00 sec)

Demonstrationseffekt savepoint, genau beobachten:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values (1);
Query OK, 1 row affected (0.00 sec)

mysql> savepoint part1;//设置一个保存点
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values (2);
Query OK, 1 row affected (0.00 sec)

mysql> rollback to part1;//将savepint = part1的语句到当前语句之间所有的操作回滚
Query OK, 0 rows affected (0.00 sec)

mysql> commit;//提交事务
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

Aus dem Obigen ist ersichtlich, dass zwei Einfügevorgänge durchgeführt wurden und schließlich nur 1 Datenelement eingefügt wurde.

savepointMüssen rollback to sp1zusammen verwendet werden, um Vorgänge zwischen sp1Speicherpunkten rollback torückgängig zu machen .

Nur-Lese-Transaktion

Dies bedeutet, dass einige schreibgeschützte Vorgänge, wie z. B. Abfragen, in der Transaktion ausgeführt werden, Einfüge-, Aktualisierungs- und Löschvorgänge jedoch nicht. Es kann zu einigen Leistungsoptimierungen für schreibgeschützte Transaktionen innerhalb der Datenbank kommen.

Die Nutzung ist wie folgt:

start transaction read only;

Beispiel:

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction read only;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    1 |
+------+
2 rows in set (0.00 sec)

mysql> delete from test1;
ERROR 1792 (25006): Cannot execute statement in a READ ONLY transaction.
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    1 |
+------+
2 rows in set (0.00 sec)

Beim Ausführen von delete in einer schreibgeschützten Transaktion wird ein Fehler gemeldet.

Einige Probleme bei der Transaktion

Diese Probleme basieren hauptsächlich auf der Sichtbarkeit von Daten über mehrere Transaktionen hinweg.

schmutzige Lektüre

Während der Ausführung liest eine Transaktion Daten, die andere Transaktionen noch nicht festgeschrieben haben.
Das ist relativ einfach zu verstehen.

gelesen verpflichtet

Im wahrsten Sinne des Wortes können wir verstehen, dass während einer Transaktionsoperation Daten gelesen werden können, die von anderen Transaktionen übermittelt wurden.

Bei jedem Lesevorgang in einer Transaktion werden die neuesten Daten gelesen, die von anderen Transaktionen in der Datenbank übermittelt wurden (entspricht dem aktuellen Lesevorgang).

wiederholbare Lektüre

Unabhängig davon, wie oft ein Lesevorgang in einem Transaktionsvorgang ausgeführt wird, ist das Leseergebnis dasselbe.

Phantomlesung

Schmutziges Lesen, nicht wiederholbares Lesen, wiederholbares Lesen, Phantomlesen, am schwierigsten zu verstehen ist Phantomlesen

Nehmen Sie MySQL als Beispiel:

Phantom-Lesevorgänge erfolgen nur im wiederholbaren Lesemodus und nicht in anderen Isolationsstufen.

Beispiele für Phantomlesephänomene:

Wenn beispielsweise im wiederholbaren Lesemodus eine Benutzertabelle mit der Mobiltelefonnummer als Primärschlüssel vorhanden ist, führen zwei Dinge die folgenden Vorgänge aus:

Der Vorgang von Transaktion A ist wie folgt:
1. Öffnen Sie die Transaktion.
2. Fragen Sie den Datensatz
mit der
Nummer wiederholbares Lesen, der gelesene Datensatz X existiert noch nicht)

Transaktion B-Vorgang: Ein Datensatz von

Die obige Operation ist wie eine Halluzination für A. Es ist klar, dass die Abfrage X (der zweite und vierte Schritt in A) nicht existiert, aber sie kann nicht erfolgreich eingefügt werden.

Das Phantomlesen kann folgendermaßen verstanden werden: Der nachfolgende Vorgang in der Transaktion (Einfügen der Nummer X) erfordert die Unterstützung des oben genannten Lesevorgangs (Abfragen des Nummerndatensatzes) Wie eine Illusion.

Wenn Sie es immer noch nicht verstehen, lesen Sie unten weiter, um später eine detaillierte Demonstration zu erhalten.

Transaktionsisolationsstufe

Wenn mehrere Transaktionen gleichzeitig stattfinden, wie kann dann die Richtigkeit der Daten in der aktuellen Transaktion sichergestellt werden? Wenn beispielsweise zwei Dinge A und B gleichzeitig stattfinden, kann A die von B übermittelten Daten sehen oder die Daten, die B nicht übermittelt hat? Dies erfordert Es hängt von der Isolationsstufe der Transaktion ab, um sicherzustellen, dass die Auswirkungen verschiedener Isolationsstufen unterschiedlich sind.

Die Transaktionsisolationsstufe löst hauptsächlich die oben genannten Probleme der Datensichtbarkeit und Datenkorrektheit zwischen mehreren Transaktionen.

Es gibt 4 Arten von Isolationsstufen:

  1. Nicht festgeschrieben lesen: READ-UNCOMMITTED

  2. Gelesener Eintrag: READ-COMMITTED

  3. Wiederholbares Lesen: REPEATABLE-READ

  4. SERIAL: SERIALISIERBAR

Die Isolationsstufen in den oben genannten vier werden immer stärker, was dazu führt, dass die Parallelität der Datenbank immer geringer wird.

Überprüfen Sie die Isolationsstufe

mysql> show variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+
1 row in set, 1 warning (0.00 sec)

Einstellungen für die Isolationsstufe

Ändern Sie die Datei in zwei Schritten und starten Sie MySQL wie folgt neu:

Ändern Sie die Datei my.init in MySQL und setzen Sie die Isolationsstufe wie folgt auf: READ-UNCOMMITTED:

# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行
transaction-isolation=READ-UNCOMMITTED

Öffnen Sie das cmd-Fenster als Administrator und starten Sie MySQL wie folgt neu:

C:\Windows\system32>net stop mysql
mysql 服务正在停止..
mysql 服务已成功停止。

C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。

Probleme, die in verschiedenen Isolationsstufen auftreten

Isolationsstufe schmutzige Lektüre nicht wiederholbares Lesen Phantomlesung
READ-UNCOMMITTED haben haben keiner
LESEN-COMMITTED keiner haben keiner
WIEDERHOLBARES LESEN keiner keiner haben
SERIALISIERBAR keiner keiner keiner

Es gibt einige Unterschiede zwischen der Tabelle und dem Internet, hauptsächlich im Bereich des Phantomlesens. Phantomlesen erscheint nur in der wiederholbaren Leseebene und existiert nicht in anderen Ebenen.

Lassen Sie uns die Sichtbarkeitsprobleme in verschiedenen Isolationsstufen demonstrieren, indem wir zwei Fenster, Fenster A und B genannt, öffnen und uns in beiden Fenstern bei MySQL anmelden.

READ-UNCOMMITTED: Nicht festgeschrieben lesen

Legen Sie die Isolationsstufe fest auf READ-UNCOMMITTED:

# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行
transaction-isolation=READ-UNCOMMITTED

MySQL neu starten:

C:\Windows\system32>net stop mysql
mysql 服务正在停止..
mysql 服务已成功停止。

C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。

Überprüfen Sie die Isolationsstufe:

mysql> show variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-UNCOMMITTED |
+-----------------------+----------------+
1 row in set, 1 warning (0.00 sec)

Löschen Sie zunächst die Daten der test1-Tabelle:

delete from test1;
select * from test1;

Führen Sie die folgenden Vorgänge in 2 Fenstern in chronologischer Reihenfolge aus:

Zeit Fenster A Fenster B
T1 Transaktion starten;
T2 wähle * aus test1;
T3 Transaktion starten;
T4 in test1 Werte einfügen (1);
T5 wähle * aus test1;
T6 wähle * aus test1;
T7 begehen;
F8 begehen;

Ein Fenster sieht wie folgt aus:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

B-Fenster ist wie folgt:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values (1);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

Schau mal:

T2-A: Keine Daten, T6-A: Es sind Daten vorhanden. B hat zum Zeitpunkt T6 nicht übermittelt. Zu diesem Zeitpunkt hat A die von B eingefügten Daten gesehen, was darauf hinweist, dass ein schmutziger Lesevorgang stattgefunden hat .

T2-A: Keine Daten, T6-A: Es sind Daten vorhanden. Die Abfrageergebnisse sind unterschiedlich, was darauf hinweist, dass ein wiederholbares Lesen nicht möglich ist .

Fazit: Wenn der Lesevorgang nicht festgeschrieben ist, können Sie die nicht festgeschriebenen Daten anderer Transaktionen lesen. Die Ergebnisse mehrerer Lesevorgänge sind unterschiedlich und es treten schmutzige Lesevorgänge und nicht wiederholbare Lesevorgänge auf.

READ-COMMITTED: gelesen, festgeschrieben

Stellen Sie die Isolationsstufe auf einREAD-COMMITTED

# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行
transaction-isolation=READ-COMMITTED

MySQL neu starten:

C:\Windows\system32>net stop mysql
mysql 服务正在停止..
mysql 服务已成功停止。

C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。

Überprüfen Sie die Isolationsstufe:

mysql> show variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+
1 row in set, 1 warning (0.00 sec)

Löschen Sie zunächst die Daten der test1-Tabelle:

delete from test1;
select * from test1;

Führen Sie die folgenden Vorgänge in 2 Fenstern in chronologischer Reihenfolge aus:

Zeit Fenster A Fenster B
T1 Transaktion starten;
T2 wähle * aus test1;
T3 Transaktion starten;
T4 in test1 Werte einfügen (1);
T5 wähle * aus test1;
T6 wähle * aus test1;
T7 begehen;
F8 wähle * aus test1;
T9 begehen;

Ein Fenster sieht wie folgt aus:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

B-Fenster ist wie folgt:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values (1);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

Schau mal:

T5-B: Es sind Daten vorhanden, T6-A-Fenster: Keine Daten, A kann die Daten von B nicht sehen, was darauf hinweist, dass kein Dirty Read vorliegt .

T6-A-Fenster: Keine Daten, T8-A: Ich habe die von B eingefügten Daten gesehen und B hat sie zu diesem Zeitpunkt übermittelt. A hat die von B übermittelten Daten gesehen, was bedeutet, dass die übermittelten Daten gelesen werden können .

T2-A, T6-A: Keine Daten, T8-A: Es liegen Daten vor. Die Ergebnisse mehrerer Messungen sind unterschiedlich, was darauf hinweist, dass eine wiederholbare Messung nicht möglich ist .

Fazit: Im Fall von Read Committed können die Daten, die nicht von anderen Transaktionen übermittelt wurden, nicht gelesen werden, aber die Daten, die von anderen Transaktionen übermittelt wurden, können gelesen werden. Die Ergebnisse mehrerer Lesevorgänge sind unterschiedlich. Es treten keine schmutzigen Lesevorgänge auf , aber Read Committed, kann nicht wiederholt gelesen werden.

REPEATABLE-READ: wiederholbares Lesen

Stellen Sie die Isolationsstufe auf einREPEATABLE-READ

# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行
transaction-isolation=REPEATABLE-READ

MySQL neu starten:

C:\Windows\system32>net stop mysql
mysql 服务正在停止..
mysql 服务已成功停止。

C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。

Überprüfen Sie die Isolationsstufe:

mysql> show variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+----------------+
1 row in set, 1 warning (0.00 sec)

Löschen Sie zunächst die Daten der test1-Tabelle:

delete from test1;
select * from test1;

Führen Sie die folgenden Vorgänge in 2 Fenstern in chronologischer Reihenfolge aus:

Zeit Fenster A Fenster B
T1 Transaktion starten;
T2 wähle * aus test1;
T3 Transaktion starten;
T4 in test1 Werte einfügen (1);
T5 wähle * aus test1;
T6 wähle * aus test1;
T7 begehen;
F8 wähle * aus test1;
T9 begehen;
T10 wähle * aus test1;

Ein Fenster sieht wie folgt aus:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    1 |
+------+
2 rows in set (0.00 sec)

B-Fenster ist wie folgt:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values (1);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    1 |
+------+
2 rows in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

Schau mal:

T2-A- und T6-A-Fenster: keine Daten, T5-B: Daten. A kann die Daten von B nicht sehen, was darauf hinweist, dass kein Dirty Read vorliegt .

T8-A: Keine Daten. B hat sie zu diesem Zeitpunkt übermittelt. A kann die von B übermittelten Daten nicht sehen. Die Ergebnisse der drei Lesevorgänge in A sind gleich, was darauf hinweist, dass keine Daten vorhanden sind, was darauf hinweist, dass der Lesevorgang wiederholt werden kann .

Fazit: Beim wiederholbaren Lesen erfolgt kein Dirty Reading, es werden keine von anderen Transaktionen übermittelten Daten gelesen und die Ergebnisse mehrerer Lesevorgänge sind konsistent, sodass der Lesevorgang wiederholt werden kann.

Demonstration des Phantomlesens

Phantom-Lesevorgänge werden nur REPEATABLE-READauf der Ebene (wiederholbarer Lesevorgang) durchgeführt, und Sie müssen zuerst die Isolationsstufe auf wiederholbare Lesevorgänge ändern.

Stellen Sie die Isolationsstufe auf einREPEATABLE-READ

# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行
transaction-isolation=REPEATABLE-READ

MySQL neu starten:

C:\Windows\system32>net stop mysql
mysql 服务正在停止..
mysql 服务已成功停止。

C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。

Überprüfen Sie die Isolationsstufe:

mysql> show variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+----------------+
1 row in set, 1 warning (0.00 sec)

Daten vorbereiten:

mysql> create table t_user(id int primary key,name varchar(16) unique key);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t_user values (1,'路人甲Java'),(2,'路人甲Java');
ERROR 1062 (23000): Duplicate entry '路人甲Java' for key 'name'

mysql> select * from t_user;
Empty set (0.00 sec)

Oben haben wir die Tabelle t_user erstellt und eine eindeutige Einschränkung für den Namen hinzugefügt, was bedeutet, dass der Name nicht wiederholt werden kann, andernfalls wird ein Fehler gemeldet.

Führen Sie die folgenden Vorgänge in 2 Fenstern in chronologischer Reihenfolge aus:

Zeit Fenster A Fenster B
T1 Transaktion starten;
T2 Transaktion starten;
T3 -- 路人甲Java
In t_user-Werte einfügen (1,'passer A Java');
T4 wähle * aus t_user;
T5 -- 查看路人甲Java是否存在
select * from t_user where name='路人甲Java';
T6 commit;
T7 -- 插入路人甲Java
insert into t_user values (2,'路人甲Java');
T8 -- 查看路人甲Java是否存在
select * from t_user where name='路人甲Java';
T9 commit;

A窗口如下:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t_user where name='路人甲Java';
Empty set (0.00 sec)

mysql> insert into t_user values (2,'路人甲Java');
ERROR 1062 (23000): Duplicate entry '路人甲Java' for key 'name'
mysql> select * from t_user where name='路人甲Java';
Empty set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

B窗口如下:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t_user values (1,'路人甲Java');
Query OK, 1 row affected (0.00 sec)

mysql> select * from t_user;
+----+---------------+
| id | name          |
+----+---------------+
|  1 | 路人甲Java    |
+----+---------------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

看一下:

A想插入数据路人甲Java,插入之前先查询了一下(T5时刻)该用户是否存在,发现不存在,然后在T7时刻执行插入,报错了,报数据已经存在了,因为T6时刻B已经插入了路人甲Java

然后A有点郁闷,刚才查的时候不存在的,然后A不相信自己的眼睛,又去查一次(T8时刻),发现路人甲Java还是不存在的。

此时A心里想:数据明明不存在啊,为什么无法插入呢?这不是懵逼了么,A觉得如同发生了幻觉一样。

SERIALIZABLE:串行

SERIALIZABLE会让并发的事务串行执行。

看效果:

将隔离级别置为SERIALIZABLE

# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行
transaction-isolation=SERIALIZABLE

重启mysql:

C:\Windows\system32>net stop mysql
mysql 服务正在停止..
mysql 服务已成功停止。

C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。

查看隔离级别:

mysql> show variables like 'transaction_isolation';
+-----------------------+--------------+
| Variable_name         | Value        |
+-----------------------+--------------+
| transaction_isolation | SERIALIZABLE |
+-----------------------+--------------+
1 row in set, 1 warning (0.00 sec)

先清空test1表数据:

delete from test1;
select * from test1;

按时间顺序在2个窗口中执行下面操作:

时间 窗口A 窗口B
T1 start transaction;
T2 select * from test1;
T3 start transaction;
T4 insert into test1 values (1);
T5 select * from test1;
T6 commit;
T7 commit;

按时间顺序运行上面的命令,会发现T4-B这样会被阻塞,直到T6-A执行完毕。

可以看出来,事务只能串行执行了。串行情况下不存在脏读、不可重复读、幻读的问题了。

关于隔离级别的选择

  1. 需要对各种隔离级别产生的现象非常了解,然后选择的时候才能游刃有余

  2. 隔离级别越高,并发性也低,比如最高级别SERIALIZABLE会让事物串行执行,并发操作变成串行了,会导致系统性能直接降低。

  3. 具体选择哪种需要结合具体的业务来选择。

  4. 读已提交(READ-COMMITTED)通常用的比较多。

总结

  1. 理解事务的4个特性:原子性、一致性、隔离性、持久性

  2. 掌握事务操作常见命令的介绍

  3. set autocommit可以设置是否开启自动提交事务

  4. start transaction:开启事务

  5. start transaction read only:开启只读事物

  6. commit:提交事务

  7. rollback:回滚事务

  8. savepoint:设置保存点

  9. rollback to 保存点:可以回滚到某个保存点

  10. 掌握4种隔离级别及了解其特点

  11. 了解脏读、不可重复读、幻读

Supongo que te gusta

Origin blog.csdn.net/weixin_46228112/article/details/132696530
Recomendado
Clasificación