Handeling Latency en transacciones MySQL
Estoy tratando de averiguar cómo configurar correctamente una transacción en una base de datos y tener en cuenta la latencia potencial.
La puesta en marchaEn mi ejemplo tengo una tabla deusers
, keys
, donde cada usuario puede tener múltiples claves, y unaconfig
tabla que determina cuántas claves puede tener cada usuario.
Quiero ejecutar un procedimiento almacenado que:
Averigua si el usuario dado puede solicitar una clave.Obtener una clave disponible, no reclamada.intenta canjear la clave para el usuario dado.El pseudocódigo para el procedimiento sería:
START TRANSACTION
(1) CALL check_permission(...,@result);
IF (@result = 'has_permission') THEN
(2) SET @unclaimed_key_id = (QUERY FOR RETURNING AVAILABLE KEY ID);
(3) CALL claim_key(@unclaimed_key_id);
END IF;
COMMIT;
El problema que estoy encontrando es que cuando simulo un retraso después de un paso1
, (mediante el usoSELECT SLEEP(<seconds>)
), es posible que un usuario determinado canjee varias claves cuando solo tienen permisos para canjear una, ejecutando el procedimiento en varias sesiones antes de que el primer procedimiento finalice su suspensión (lo que, de nuevo, es simular un retraso)
Aquí está el código paralas mesas ylos procedimientos (nota: para el pequeño ejemplo no me molesté con los índices y las claves externas, pero obviamente las uso en el proyecto real).
Para ver mi problema, simplemente configure las tablas y los procedimientos en una base de datos, luego abra dos terminales mysql, y en la primera ejecución esto:
CALL `P_user_request_key`(10,1,@out);
SELECT @out;
Y luego rápidamente (tienes 10 segundos) en la segunda ejecución de esto:
CALL `P_user_request_key`(0,1,@out);
SELECT @out;
Ambas consultas volverán con éxitokey_claimed
y UsuarioBob
terminará con 4 teclas asignadas a él, aunque el valor máximo en la configuración se establece en 3 por usuario.