Invece di FOR UPDATE
usa LOCK IN SHARE MODE
. FOR UPDATE
impedisce anche ad altre transazioni di leggere la riga. LOCK IN SHARE MODE
consente la lettura, ma impedisce l'aggiornamento.
Riferimento:Manuale MySQL
------ sessione 1
START TRANSACTION;
SELECT * FROM test WHERE t=1 LOCK IN SHARE MODE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;
----- sessione 2 (che non viene più bloccata :))
START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;
Aggiornamento:
Rendendosi conto che la tabella non ha indice su t
, ho la seguente spiegazione:
Innanzitutto, la transazione T1 blocca la riga 1 in SELECT * FROM test WHERE t=1 FOR UPDATE
Successivamente, la transazione T2 tenta di eseguire UPDATE test SET NAME='irfandd' WHERE t=4
. Per scoprire quali righe sono interessate, è necessario eseguire la scansione di tutte le righe, inclusa la riga 1 . Ma questo è bloccato, quindi T2 deve attendere fino al termine di T1. Se è presente un qualsiasi tipo di indice, WHERE t=4
può utilizzare l'indice per decidere se riga 1 contiene t=4
o no, quindi non c'è bisogno di aspettare.
Opzione 1: aggiungi un indice su test.t
così il tuo aggiornamento può usarlo.
Opzione 2: usa LOCK IN SHARE MODE
, che ha lo scopo di inserire un blocco di sola lettura. Sfortunatamente questa opzione crea un deadlock. È interessante notare che la transazione T2 viene eseguita (aggiornamento della riga 4) e T1 non riesce (aggiornamento della riga 2). Sembra che T1 blocchi in lettura riga 4 inoltre, e poiché T2 lo modifica, T1 non riesce a causa del livello di isolamento della transazione (LETTURA RIPETIBILE per impostazione predefinita
). La soluzione finale sarebbe giocare con Livelli di isolamento della transazione , utilizzando READ UNCOMMITTED
o READ COMMITTED
livelli di transazione.
La più semplice è Opzione 1 , IMHO, ma dipende dalle tue possibilità.