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 TransaktionsisolationsstufenREAD UNCOMMITTED
oder READ COMMITTED
Transaktionsebenen.
Am einfachsten ist Option 1 , IMHO, aber es liegt an Ihren Möglichkeiten.