Heim  >  Artikel  >  Datenbank  >  Eine kurze Analyse der Transaktionsisolationsstufe in MySQL und eine Diskussion seiner Implementierungsprinzipien

Eine kurze Analyse der Transaktionsisolationsstufe in MySQL und eine Diskussion seiner Implementierungsprinzipien

青灯夜游
青灯夜游nach vorne
2022-03-08 10:21:542184Durchsuche

Dieser Artikel wird Ihnen helfen, die Transaktionen in MySQL zu verstehen und über das Implementierungsprinzip der Transaktionsisolation zu sprechen. Ich hoffe, er kann Ihnen helfen!

Eine kurze Analyse der Transaktionsisolationsstufe in MySQL und eine Diskussion seiner Implementierungsprinzipien

Apropos Datenbanktransaktionen: Eine Menge transaktionsbezogenes Wissen muss jedem leicht in den Sinn kommen, wie zum Beispiel die ACID-Eigenschaften von Transaktionen, Isolationsstufen, gelöste Probleme (Dirty Reads, nicht wiederholbare Lesevorgänge, Phantom Reads). usw., aber nur wenige Menschen wissen möglicherweise wirklich, wie diese Merkmale von Transaktionen implementiert werden und warum es vier Isolationsstufen gibt.

Heute werden wir zunächst über das Implementierungsprinzip der Transaktionsisolation in MySQL sprechen und in Zukunft weiterhin Artikel veröffentlichen, um die Implementierungsprinzipien anderer Funktionen zu analysieren.

Natürlich ist MySQL umfangreich und tiefgreifend, und Auslassungen im Artikel sind unvermeidlich.

Erklärung

Die Transaktionsimplementierungslogik von MySQL befindet sich auf der Engine-Ebene und nicht alle Engines unterstützen Transaktionen. Die folgenden Anweisungen basieren auf der InnoDB-Engine.

Definition

Isolation bezieht sich auf die Tatsache, dass nach der Übermittlung und Ausführung verschiedener Transaktionen nacheinander der endgültige Effekt seriell ist. Das heißt, dass bei einer Transaktion die Daten, die sie während ihrer Ausführung wahrnimmt, nur durch Änderungen verursacht werden sollten Ihre eigenen Vorgänge, und es sollten keine Datenänderungen durch andere Transaktionen auftreten.

Isolation löst das Problem gleichzeitiger Transaktionen.

Standard-SQL-Isolationsstufe

Der einfachste Weg, die Isolation zu implementieren, besteht darin, dass jede Transaktion seriell ausgeführt wird. Wenn die vorherige Transaktion nicht abgeschlossen wurde, warten nachfolgende Transaktionen. Allerdings ist diese Implementierungsmethode bei Parallelität offensichtlich nicht sehr effizient und nicht für den Einsatz in tatsächlichen Umgebungen geeignet.

Um die oben genannten Probleme zu lösen und unterschiedliche Ebenen der Parallelitätskontrolle zu erreichen, haben die Hersteller von SQL-Standards verschiedene Isolationsstufen vorgeschlagen: nicht festgeschriebenes Lesen (nicht festgeschriebenes Lesen), festgeschriebenes Lesen (festgeschriebenes Lesen), wiederholbares Lesen (wiederholbares Lesen), Sequenz Serialisierbar. Die fortschrittlichste Isolationsstufe ist das serialisierte Lesen. In anderen Isolationsstufen sind einige Probleme mehr oder weniger zulässig, da Transaktionen gleichzeitig ausgeführt werden. Siehe die folgende Matrixtabelle:

?? kann wiederholt gelesen werden Sequenz Chemisch.                                                                                    

Beachten Sie, dass die InnoDB-Engine von MySQL das Phantom-Leseproblem durch Lückensperren auf der Ebene der wiederholbaren Lesevorgänge löst und das Problem der nicht wiederholbaren Lesevorgänge durch MVCC löst. Weitere Informationen finden Sie in der folgenden Analyse.

Implementierungsprinzip

Standard-SQL-Transaktionsisolationsstufen-Implementierungsprinzip

Das Problem, auf das wir oben gestoßen sind, ist tatsächlich das Kontrollproblem bei gleichzeitigen Transaktionen. Die häufigste Methode zur Lösung gleichzeitiger Transaktionen ist die pessimistische Parallelitätskontrolle (dh Sperren in der Datenbank). . Die Implementierung der standardmäßigen SQL-Transaktionsisolationsstufe basiert auf Sperren. Schauen wir uns an, wie sie implementiert wird:

Isolationsstufe (+: darf auftreten, -: darf nicht auftreten) Dirty Read non-repeatable Read Phantom Read
- +
Transaktionsisolationsstufe                                      Uncommitted Read (RU)Transaktionspaar Die aktuell gelesenen Daten sind nicht gesperrt; In dem Moment, in dem eine Transaktion bestimmte Daten aktualisiert (d. h. in dem Moment, in dem die Aktualisierung erfolgt), muss zunächst eine hinzugefügt werden, die erst am Ende der Transaktion freigegeben wird. Die Transaktion fügt eine gemeinsame Sperre auf Zeilenebene (nur beim Lesen gesperrt) zu den aktuell gelesenen Daten hinzu. Sobald die Zeile gelesen wurde, wird die gemeinsame Sperre auf Zeilenebene sofort aufgehoben. Wenn eine Transaktion bestimmte Daten aktualisiert (d. h. in dem Moment, in dem die Aktualisierung erfolgt), muss zunächst eine In dem Moment, in dem eine Transaktion bestimmte Daten liest (d. h. in dem Moment, in dem sie mit dem Lesen beginnt), muss sie zunächst eine gemeinsame Sperre auf Zeilenebene hinzufügen, die erst am Ende freigegeben wird der Transaktion; Transaktion In dem Moment, in dem bestimmte Daten aktualisiert werden (d. h. in dem Moment, in dem die Aktualisierung erfolgt), muss ihnen zuerst eine Wenn eine Transaktion Daten liest, muss sie zunächst eine gemeinsame Sperre auf Tabellenebene hinzufügen, die erst am Ende der Transaktion freigegeben wird; Wenn eine Transaktion aktualisiert wird Daten müssen zunächst hinzugefügt werden. Die exklusive Sperre auf Tabellenebene wird erst am Ende der Transaktion freigegeben.
gemeinsame Sperre auf Zeilenebene

Read Committed (RC)
exklusive Sperre auf Zeilenebene hinzugefügt werden, die erst am Ende der Transaktion freigegeben wird.

Repeatable Read (RR)
exklusive Sperre auf Zeilenebene hinzugefügt werden, die erst freigegeben wird das Ende der Transaktion.

Serialisiertes Lesen (S)

Es ist ersichtlich, dass, wenn nur Sperren zur Implementierung der Isolationsstufensteuerung verwendet werden, häufiges Sperren und Entsperren erforderlich ist und leicht Lese- und Schreibkonflikte auftreten können (z. B. aktualisiert Transaktion A auf RC-Ebene Datenzeile 1 und Transaktion B Bevor dann Transaktion A festgeschrieben wird, muss die Lesedatenzeile 1 darauf warten, dass Transaktion A festgeschrieben und die Sperre aufgehoben wird.

Um das Problem von Lese- und Schreibkonflikten ohne Sperren zu lösen, hat MySQL den MVCC-Mechanismus eingeführt. Weitere Informationen finden Sie in meinem vorherigen Analyseartikel: Optimistische Sperren, pessimistische Sperren und MVCC in der Datenbank in einem Artikel verstehen.

Implementierungsprinzip der InnoDB-Transaktionsisolationsebene

Bevor wir mit der Analyse fortfahren, müssen wir zunächst einige Konzepte verstehen:

1 Transaktion, sperren Sie das Lesen aktiv, z. B. SELECT ... LOCK IN SHARE MODE und SELECT ... FOR UPDATE. Es werden jeweils gemeinsame Zeilensperren und exklusive Zeilensperren hinzugefügt. Die Klassifizierung von Sperren finden Sie in meinem vorherigen Analyseartikel: MySQL-Sperrklassifizierungen, die Sie kennen sollten.

https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html

Konsistente nicht sperrende Lesevorgänge

: InnoDB verwendet MVCC, um einen bestimmten Zeitpunkt für Transaktionsabfragen bereitzustellen Datenbank-Snapshot. Die Abfrage erkennt Änderungen, die von vor diesem Zeitpunkt festgeschriebenen Transaktionen vorgenommen wurden, jedoch keine Änderungen, die von späteren oder nicht festgeschriebenen Transaktionen (außer dieser Transaktion) vorgenommen wurden. Das heißt, nach dem Start einer Transaktion sind die von der Transaktion angezeigten Daten die Daten zum Zeitpunkt des Transaktionsstarts, und spätere Änderungen anderer Transaktionen sind in dieser Transaktion nicht sichtbar.
Konsistentes Lesen ist der Standardmodus von InnoDB für die Verarbeitung von SELECT-Anweisungen auf den Isolationsstufen RC und RR. Konsistente, nicht sperrende Lesevorgänge setzen keine Sperren für die Tabellen, auf die sie zugreifen. Während also konsistente, nicht sperrende Lesevorgänge für die Tabellen ausgeführt werden, können andere Transaktionen diese gleichzeitig lesen oder ändern.

https://dev.mysql.com/doc/refman/8.0/en/innodb-consistent-read.html

2. Aktueller Read und Snapshot Read

Der aktuelle Read

ist Read The neueste Version, wie

UPDATE, DELETE, INSERT, SELECT... LOCK IN SHARE MODE, SELECT... FOR UPDATEDiese Vorgänge sind alle aktuelle Lesevorgänge. Warum werden sie aktuelle Lesevorgänge genannt? Das heißt, es liest die neueste Version des Datensatzes. Beim Lesen muss auch sichergestellt werden, dass andere gleichzeitige Transaktionen den aktuellen Datensatz nicht ändern können und der gelesene Datensatz gesperrt wird.

Snapshot-Lesen

liest die Snapshot-Version, bei der es sich um die historische Version handelt. Der

SELECT-Vorgang ist ein Snapshot-Lesen, also ein nicht blockierendes Lesen ohne Sperren. Die Voraussetzung für das Snapshot-Lesen ist die Isolationsstufe Es handelt sich nicht um die Ebenen „Uncommitted Read“ und „Serialized Read“, da beim Uncommitted Read immer die neueste Datenzeile gelesen wird und nicht die Datenzeile, die der aktuellen Transaktionsversion entspricht, und das Serialized Read die Tabelle sperrt

. 3. Implizites Sperren und explizites Sperren Sperre bei Bedarf entsprechend der Isolationsstufe;

Die Sperre wird nur aufgehoben, wenn ein Commit oder Rollback ausgeführt wird, und alle Sperren werden gleichzeitig aufgehoben.

Explizites Sperren

InnoDB unterstützt auch explizites Sperren (Storage-Engine-Schicht) durch spezifische Anweisungen

select ... lock in share mode //共享锁
select ... for update //排他锁

Explizites Sperren der MySQL-Server-Schicht:

lock table
unlock table
  • Nachdem wir die oben genannten Konzepte verstanden haben, nehmen wir eine Schauen Sie sich an, wie InnoDB-Transaktionen implementiert werden (die folgenden Lesungen beziehen sich alle auf nicht aktiv gesperrte Auswahlen)
  • 事务隔离级别    实现方式                                                     
    未提交读(RU) 事务对当前被读取的数据不加锁,都是当前读

    事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加行级共享锁,直到事务结束才释放。
    提交读(RC)    事务对当前被读取的数据不加锁,且是快照读

    事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加行级排他锁(Record),直到事务结束才释放。
    可重复读(RR) 事务对当前被读取的数据不加锁,且是快照读

    事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加行级排他锁(Record,GAP,Next-Key),直到事务结束才释放。

    通过间隙锁,在这个级别MySQL就解决了幻读的问题

    通过快照,在这个级别MySQL就解决了不可重复读的问题
    序列化读(S)   事务在读取数据时,必须先对其加表级共享锁 ,直到事务结束才释放,都是当前读

    事务在更新数据时,必须先对其加表级排他锁 ,直到事务结束才释放。

    可以看到,InnoDB通过MVCC很好的解决了读写冲突的问题,而且提前一个级别就解决了标准级别下会出现的幻读问题,大大提升了数据库的并发能力。

    一些常见误区

    幻读到底包不包括了delete的情况?

    不可重复读:前后多次读取一行,数据内容不一致,针对其他事务的update和delete操作。为了解决这个问题,使用行共享锁,锁定到事务结束(也就是RR级别,当然MySQL使用MVCC在RC级别就解决了这个问题)

    幻读:当同一个查询在不同时间生成不同的行集合时就是出现了幻读,针对的是其他事务的insert操作,为了解决这个问题,锁定整个表到事务结束(也就是S级别,当然MySQL使用间隙锁在RR级别就解决了这个问题)

    网上很多文章提到幻读和提交读的时候,有的说幻读包括了delete的情况,有的说delete应该属于提交读的问题,那到底真相如何呢?我们实际来看下MySQL的官方文档(如下)

    The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT) is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.

    https://dev.mysql.com/doc/refman/5.7/en/innodb-next-key-locking.html

    可以看到,幻读针对的是结果集前后发生变化,所以看起来delete的情况应该归为幻读,但是我们实际分析下上面列出的标准SQL在RR级别的实现原理就知道,标准SQL的RR级别是会对查到的数据行加行共享锁,所以这时候其他事务想删除这些数据行其实是做不到的,所以在RR下,不会出现因delete而出现幻读现象,也就是幻读不包含delete的情况。

    MVCC能解决了幻读问题?

    网上很多文章会说MVCC或者MVCC+间隙锁解决了幻读问题,实际上MVCC并不能解决幻读问题。如以下的例子:

    begin;
    
    #假设users表为空,下面查出来的数据为空
    
    select * from users; #没有加锁
    
    #此时另一个事务提交了,且插入了一条id=1的数据
    
    select * from users; #读快照,查出来的数据为空
    
    update users set name='mysql' where id=1;#update是当前读,所以更新成功,并生成一个更新的快照
    
    select * from users; #读快照,查出来id为1的一条记录,因为MVCC可以查到当前事务生成的快照
    
    commit;

    可以看到前后查出来的数据行不一致,发生了幻读。所以说只有MVCC是不能解决幻读问题的,解决幻读问题靠的是间隙锁。如下:

    begin;
    
    #假设users表为空,下面查出来的数据为空
    
    select * from users lock in share mode; #加上共享锁
    
    #此时另一个事务B想提交且插入了一条id=1的数据,由于有间隙锁,所以要等待
    
    select * from users; #读快照,查出来的数据为空
    
    update users set name='mysql' where id=1;#update是当前读,由于不存在数据,不进行更新
    
    select * from users; #读快照,查出来的数据为空
    
    commit;
    
    #事务B提交成功并插入数据

    注意,RR级别下想解决幻读问题,需要我们显式加锁,不然查询的时候还是不会加锁的

    原文地址:https://segmentfault.com/a/1190000025156465

    作者: X先生

    【相关推荐:mysql视频教程

Das obige ist der detaillierte Inhalt vonEine kurze Analyse der Transaktionsisolationsstufe in MySQL und eine Diskussion seiner Implementierungsprinzipien. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen