I stedet for FOR UPDATE
brug LOCK IN SHARE MODE
. FOR UPDATE
forhindrer andre transaktioner i også at læse rækken. LOCK IN SHARE MODE
tillader læsning, men forhindrer opdatering.
Reference: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 ikke blokeres længere :) )
START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;
Opdatering:
Indser, at tabellen ikke har noget indeks på t
, jeg har følgende forklaring:
Først låser transaktion T1 række 1 i SELECT * FROM test WHERE t=1 FOR UPDATE
Dernæst forsøger transaktion T2 at udføre UPDATE test SET NAME='irfandd' WHERE t=4
. For at finde ud af, hvilke række(r) der er berørt, skal den scanne alle rækker, inklusive række 1 . Men den er låst, så T2 skal vente, indtil T1 er færdig. Hvis der er nogen form for indeks, vises WHERE t=4
kan bruge indekset til at afgøre, om række 1 indeholder t=4
eller ej, så ingen grund til at vente.
Mulighed 1: tilføje et indeks på test.t
så din opdatering kan bruge den.
Mulighed 2: brug LOCK IN SHARE MODE
, som kun er beregnet til at sætte en læselås. Desværre skaber denne mulighed en deadlock. Interessant nok udføres T2-transaktionen (opdatering af række 4), og T1 mislykkes (opdatering af række 2). Det ser ud til, at T1 læselåser række 4 også, og da T2 ændrer det, fejler T1 på grund af transaktionsisolationsniveauet (Gentagelig LÆSning som standard
). Den endelige løsning ville være at lege med Transaktionsisolationsniveauer , ved hjælp af READ UNCOMMITTED
eller READ COMMITTED
transaktionsniveauer.
Den enkleste er Mulighed 1 , IMHO, men det er op til dine muligheder.