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à.