Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Sperren auf Zeilenebene in MySQL

Statt FOR UPDATE Verwenden Sie den LOCK IN SHARE MODE . FOR UPDATE verhindert, dass andere Transaktionen die Zeile ebenfalls lesen. LOCK IN SHARE MODE erlaubt lesen, verhindert aber aktualisieren.

Referenz:MySQL-Handbuch

------ Sitzung 1

START TRANSACTION;
SELECT * FROM test WHERE t=1 LOCK IN SHARE MODE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;

----- Sitzung 2 (die nicht mehr blockiert wird :) )

START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;

Aktualisierung:

Erkennen, dass die Tabelle keinen Index hat auf t , habe ich folgende Erklärung:

Zuerst sperrt Transaktion T1 die Zeile 1 in SELECT * FROM test WHERE t=1 FOR UPDATE

Als nächstes versucht Transaktion T2, UPDATE test SET NAME='irfandd' WHERE t=4 auszuführen . Um herauszufinden, welche Zeile(n) betroffen sind, müssen alle Zeilen gescannt werden, einschließlich Zeile 1 . Aber das ist gesperrt, also muss T2 warten, bis T1 fertig ist. Wenn es irgendeine Art von Index gibt, WHERE t=4 kann den Index verwenden, um zu entscheiden, ob Zeile 1 enthält t=4 oder nicht, also brauchen Sie nicht zu warten.

Möglichkeit 1: füge einen Index zu test.t hinzu damit Ihr Update es verwenden kann.

Option 2: Verwenden Sie den LOCK IN SHARE MODE , die nur zum Setzen einer Lesesperre gedacht ist. Leider erzeugt diese Option einen Deadlock. Interessanterweise wird die T2-Transaktion ausgeführt (Aktualisierung von Zeile 4) und T1 schlägt fehl (Aktualisierung von Zeile 2). Es scheint, dass T1 Zeile 4 mit Lesesperren sperrt und da T2 es modifiziert, schlägt T1 aufgrund der Transaktionsisolationsstufe fehl (WIEDERHOLBARES LESEN standardmäßig ). Die endgültige Lösung wäre, mit Transaktionsisolationsstufen , mit READ UNCOMMITTED oder READ COMMITTED Transaktionsebenen.

Am einfachsten ist Option 1 , IMHO, aber es liegt an Ihren Möglichkeiten.