En lugar de FOR UPDATE
use LOCK IN SHARE MODE
. FOR UPDATE
evita que otras transacciones también lean la fila. LOCK IN SHARE MODE
permite la lectura, pero impide la actualización.
Referencia:Manual de MySQL
------ sesión 1
START TRANSACTION;
SELECT * FROM test WHERE t=1 LOCK IN SHARE MODE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;
----- sesión 2 (que ya no está bloqueada :) )
START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;
Actualización:
Darse cuenta de que la tabla no tiene índice en t
, tengo la siguiente explicación:
Primero, la transacción T1 bloquea la fila 1 en SELECT * FROM test WHERE t=1 FOR UPDATE
A continuación, la transacción T2 intenta ejecutar UPDATE test SET NAME='irfandd' WHERE t=4
. Para averiguar qué filas están afectadas, debe escanear todas las filas, incluida la fila 1 . Pero eso está bloqueado, por lo que T2 debe esperar hasta que finalice T1. Si hay algún tipo de índice, WHERE t=4
puede usar el índice para decidir si fila 1 contiene t=4
o no, así que no hay necesidad de esperar.
Opción 1: agregue un índice en test.t
para que su actualización pueda usarlo.
Opción 2: use LOCK IN SHARE MODE
, que está destinado a poner un bloqueo de lectura únicamente. Desafortunadamente, esta opción crea un punto muerto. Curiosamente, la transacción T2 se ejecuta (actualizando la fila 4) y T1 falla (actualizando la fila 2). Parece que T1 bloquea la lectura fila 4 además, y como T2 lo modifica, T1 falla por el nivel de aislamiento de la transacción (LECTURA REPETIBLE por defecto
). La solución final sería jugar con Niveles de aislamiento de transacciones , usando READ UNCOMMITTED
o READ COMMITTED
niveles de transacciones.
La más simple es Opción 1 , en mi humilde opinión, pero depende de tus posibilidades.