MySQL Tabellensperrung: Halter liest und schreibt, andere Sitzungen nur gelesen?

8

Ist es möglich, eine Tabelle so zu sperren, dass der Inhaber lesen und schreiben kann und andere Sitzungen nur lesen können?

Die Dokumentation scheint anzudeuten, dass eine Lesesperre allen nur erlaubt Lesen, und eine Schreibsperre erlaubt nur dem Inhaber zu lesen und zu schreiben und andere Sitzungen haben keinen Zugriff. Es scheint so, als wäre der Inhaber in der Lage zu lesen und zu schreiben, und andere Sitzungen, die nur lesen können, wären ein ziemlich häufig benötigtes Verhalten - vielleicht das am häufigsten benötigte Verhalten.

Vielleicht wäre die Leistung bei der Implementierung dieses Szenarios zu hoch?

    
John Bachir 24.10.2011, 21:39
quelle

4 Antworten

3

Sehen Sie sich LOCK IN SHARE MODE an.

Damit können Sie nicht blockierende Lesesperren setzen.

Aber denken Sie daran, dies kann zu Deadlocks führen! Stellen Sie sicher, dass Sie mit Prozessen mit veralteten Informationen einverstanden sind.

    
Byron Whitlock 24.10.2011 21:49
quelle
3

Es gibt viele korrekte Wörter in vorhandenen Antworten, aber niemand scheint eine klare Antwort gegeben zu haben. Ich werde es versuchen.

Wie Sie bereits in der Dokumentation zu LOCK TABLES gesehen haben, ist dies möglich nicht für den Zweck verwendet werden, da für die READ lock:

  

Die Sitzung, die die Sperre hält, kann die Tabelle lesen (aber nicht schreiben).

und für die WRITE lock:

  

Nur die Sitzung, die die Sperre enthält, kann auf die Tabelle zugreifen. Keine andere Sitzung kann darauf zugreifen, bis die Sperre aufgehoben wird.

Das ist der Effekt, der kaum mit einer beliebigen Engine-Tabelle erreicht werden kann, aber es kann mit einer Transaktions-Engine erreicht werden, das heißt InnoDB.

Denken wir darüber nach, was bedeutet, dass eine einzelne Sitzung eine konstante Schreibsperre für eine Tabelle behält und andere Tabellen Daten aus der Tabelle in Bezug auf Transaktionen lesen können. Das bedeutet, dass wir eine offene Long-Living-Transaktion haben (es sei W transaction), die eine Tabelle für Änderungen sperrt und andere Transaktionen (in anderen Sitzungen) Daten lesen können, die bereits modifiziert, aber noch nicht festgeschrieben sind. In Bezug auf Isolationsebenen bedeutet das, dass wir die Standardisolationsstufe auf READ-UNCOMMITTED einrichten sollten, damit wir die Isolationsstufe für jede neue Sitzung nicht ändern müssen:

%Vor%

Aber unsere Transaktion W sollte eine stärkere Isolationsstufe verwenden, andernfalls können wir keine Sperre auf unsere Tabelle anwenden. READ-COMMITTED ist nicht stark genug, aber REPEATABLE-READ ist genau das, was wir wollen. Vor dem Start einer W Transaktion sollten wir die Transaktionsebene für die aktuelle Sitzung festlegen:

%Vor%

Nun, wie Sie die ganze Tabelle sperren. Lassen Sie uns eine Tabelle erstellen:

%Vor%

LOCK IN SHARE-MODUS ist nicht das, was wir wollen:

  

Wenn eine dieser Zeilen [die gelesen werden] durch eine andere Transaktion geändert wurde, die noch nicht festgeschrieben wurde, wartet Ihre Abfrage bis zum Ende dieser Transaktion und verwendet dann die neuesten Werte.

LOCK FOR UPDATE scheint zu tun, was wir brauchen:

  

SELECT ... FOR UPDATE sperrt die Zeilen und alle zugehörigen Indexeinträge.

Jetzt brauchen wir nur noch die Zeilen zu sperren. Das Einfachste, was wir tun können, ist, den Primärschlüssel zu sperren. COUNT(*) führt eine vollständige Indexsuche nach InnoDB durch (da InnoDB die genaue Zeilenanzahl nicht kennt).

%Vor%

Jetzt können Sie andere Sitzungen öffnen und versuchen, die Daten aus der Tabelle zu lesen und versuchen, die vorhandenen Daten aus diesen Sitzungen hinzuzufügen oder zu ändern.

Das Problem ist jedoch, dass Sie die Änderungen in W festschreiben sollten, und sobald Sie die Transaktion festschreiben, wird die Sperre aufgehoben und alle wartenden Einfügungen oder Aktualisierungen werden ebenfalls angewendet, selbst wenn Sie sie mit folgendem Befehl festschreiben:

%Vor%

Die Moral der Geschichte ist, dass es viel einfacher ist, zwei MySQL-Konten zu haben: a) ein Konto mit INSERT, UPDATE und DELETE schreiben GRANT Berechtigungen , und b) lesen Konto, das nicht hat.

    
newtover 13.12.2012 11:50
quelle
0

Es gibt SELECT ... FOR UPDATE , mit denen die Zeilen gesperrt werden für andere Anrufer, die SELECT ... FOR UPDATE haben, aber nicht für alle, die nur SELECT tun. UPDATE s wartet ebenfalls auf die Sperre.

Dies ist nützlich, wenn Sie einen Wert abrufen und dann ein Update zurückschieben möchten, ohne dass jemand den Wert ändert und Sie nicht bemerken. Seien Sie vorsichtig, wenn Sie zu viel davon hinzufügen, geraten Sie in eine Sackgasse.

    
Emil Ivanov 13.12.2012 07:37
quelle
-1

Sie können feststellen, dass die InnoDB-Engine standardmäßig das tut, was Sie benötigen: Schreibvorgänge blockieren Lesevorgänge nicht. Sie müssen mit der Transaktionsisolationsstufe vorsichtig sein, damit Schreibvorgänge verfügbar sind, wenn Sie sie benötigen.

    
Joshua Martell 24.10.2011 22:00
quelle