mysql sql transactions race-condition

Cómo evitar la condición de carrera en MySQL



transactions race-condition (1)

Tengo una condición de carrera potencial en una aplicación que estoy desarrollando, que me gustaría explicar y evitar en mi consulta.

Para resumir el flujo de la aplicación ...

  1. Crea una nueva fila en la tabla de entries :

    INSERT INTO entries ( name, email ) VALUES ( ''Foo Bar'', ''[email protected]'' );

  2. Averigüe si el Sr. Bar es un ganador al consultar una tabla de prizes :

    SELECT id FROM prizes WHERE various_time_conditions = ''met'' AND id NOT IN ( SELECT prize_id FROM entries );

  3. Si él es un ganador, actualice su fila de entrada en consecuencia:

    UPDATE entries SET prize_id = [prize id] WHERE id = [entry id];

Como cada premio solo puede entregarse una vez, necesito eliminar cualquier posibilidad de una condición de carrera donde otro proceso pueda consultar la tabla de premios y actualizar la tabla de entrada entre los pasos 2 y 3 anteriores.

He estado investigando un poco y he encontrado un montón de información sobre transacciones (todas mis tablas usan InnoDB) y el uso de la sintaxis SELECT ... FOR UPDATE MySQL, pero no estoy seguro de cuál es la solución más adecuada para mí.


Vas a querer bloquear el registro del premio. Así que agrega un indicador de disponibilidad en la tabla de premios (quizás con un valor predeterminado) si no vas a usar algo como un winner_id. Algo como esto:

SELECT id FROM prizes WHERE ... AND available = 1 FOR UPDATE

Luego, configure la disponibilidad si asigna el premio:

UPDATE prizes SET available = 0 WHERE id = ...

Tendrá que envolver esto dentro de una transacción, por supuesto.

Asegúrese de que cada vez que compruebe si el premio está disponible, agregue AND available = 1 FOR UPDATE a la consulta porque un SELECT sin la FOR UPDATE no va a esperar un bloqueo.