Istället för FOR UPDATE
använd LOCK IN SHARE MODE
. FOR UPDATE
förhindrar att andra transaktioner också läser raden. LOCK IN SHARE MODE
tillåter läsning, men förhindrar uppdatering.
Referens:MySQL Manual
------ session 1
START TRANSACTION;
SELECT * FROM test WHERE t=1 LOCK IN SHARE MODE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;
----- session 2 (som inte blockeras längre :) )
START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;
Uppdatering:
Inser att tabellen inte har något index på t
, jag har följande förklaring:
Först låser transaktion T1 rad 1 i SELECT * FROM test WHERE t=1 FOR UPDATE
Därefter försöker transaktion T2 att utföra UPDATE test SET NAME='irfandd' WHERE t=4
. För att ta reda på vilka rader som berörs måste den skanna alla rader, inklusive rad 1 . Men det är låst, så T2 måste vänta tills T1 är klart. Om det finns någon form av index visas WHERE t=4
kan använda indexet för att avgöra om rad 1 innehåller t=4
eller inte, så du behöver inte vänta.
Alternativ 1: lägg till ett index på test.t
så att din uppdatering kan använda den.
Alternativ 2: använd LOCK IN SHARE MODE
, som endast är avsedd för att sätta ett läslås. Tyvärr skapar detta alternativ ett dödläge. Intressant nog utförs T2-transaktionen (uppdatering av rad 4) och T1 misslyckas (uppdatering av rad 2). Det verkar som att T1 läslås rad 4 också, och eftersom T2 modifierar det, misslyckas T1 på grund av transaktionsisoleringsnivån (REPETERBAR LÄSNING som standard
). Den slutliga lösningen skulle vara att leka med Transaktionsisoleringsnivåer , med hjälp av READ UNCOMMITTED
eller READ COMMITTED
transaktionsnivåer.
Det enklaste är Alternativ 1 IMHO, men det är upp till dina möjligheter.