Místo FOR UPDATE
použijte LOCK IN SHARE MODE
. FOR UPDATE
zabrání dalším transakcím číst řádek také. LOCK IN SHARE MODE
umožňuje čtení, ale brání aktualizaci.
Odkaz:Příručka MySQL
------ relace 1
START TRANSACTION;
SELECT * FROM test WHERE t=1 LOCK IN SHARE MODE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;
----- relace 2 (která již není blokována :) )
START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;
Aktualizace:
Uvědomte si, že tabulka nemá žádný index na t
, mám následující vysvětlení:
Nejprve transakce T1 uzamkne řádek 1 v SELECT * FROM test WHERE t=1 FOR UPDATE
Dále se transakce T2 pokusí provést UPDATE test SET NAME='irfandd' WHERE t=4
. Aby zjistil, které řádky jsou ovlivněny, musí prohledat všechny řádky, včetně řádku 1 . Ale to je uzamčeno, takže T2 musí počkat, až T1 skončí. Pokud existuje nějaký druh indexu, WHERE t=4
může použít index k rozhodnutí, zda řádek 1 obsahuje t=4
nebo ne, takže není třeba čekat.
Možnost 1: přidejte index na test.t
aby ji vaše aktualizace mohla použít.
Možnost 2: použijte LOCK IN SHARE MODE
, který je určen pouze pro vložení zámku pro čtení. Tato možnost bohužel vytváří uváznutí. Zajímavé je, že transakce T2 se provede (aktualizace řádku 4) a T1 selže (aktualizace řádku 2). Zdá se, že T1 blokuje čtení řádku 4 také, a protože to T2 upravuje, T1 selže kvůli úrovni izolace transakcí (Opakovatelné čtení ve výchozím nastavení
). Konečným řešením by bylo hraní s Úrovně izolace transakcí , pomocí READ UNCOMMITTED
nebo READ COMMITTED
úrovně transakcí.
Nejjednodušší je Možnost 1 IMHO, ale je to na vašich možnostech.