Mysql
 sql >> Database >  >> RDS >> Mysql

Blocco a livello di riga in MySQL

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