Bloqueos Físicos de Filas, Concurrencia y Deadlocks
En entornos transaccionales de alta concurrencia (como reservas de vuelos, compra de entradas o cobros en pasarelas bancarias), múltiples procesos intentan leer y actualizar el mismo registro exactamente al mismo tiempo.
Para evitar condiciones de carrera (Race Conditions) donde dos usuarios compran la última unidad de inventario disponible, el SGBD proporciona mecanismos de bloqueo físico a nivel de fila (Row-Level Locking).
1. Bloqueo Exclusivo de Filas: SELECT ... FOR UPDATE #
Cuando una transacción ejecuta un SELECT ... FOR UPDATE, el motor relacional adquiere un bloqueo exclusivo (Exclusive Lock) sobre las filas devueltas. Ninguna otra transacción podrá modificar o bloquear esas mismas filas hasta que la primera ejecute COMMIT o ROLLBACK.
Ejemplo Práctico: Reserva de Stock de Inventario #
1BEGIN; 2 -- Bloquear la fila del producto 101 para lectura y posterior actualización 3 SELECT stock FROM productos WHERE id_producto = 101 FOR UPDATE; 4 5 -- Comprobar si hay stock suficiente en la aplicación y restar 1 6 UPDATE productos SET stock = stock - 1 WHERE id_producto = 101; 7COMMIT;
- Si otra transacción intenta consultar o modificar el producto 101 simultáneamente con
FOR UPDATE, quedará pausada en espera hasta que la primera transacción confirme.
2. Modos de Control de Espera: NOWAIT y SKIP LOCKED #
Por defecto, si una fila está bloqueada, las demás transacciones esperan indefinidamente (o hasta que venza el lock_timeout). Para evitar bloqueos prolongados se utilizan dos cláusulas fundamentales:
NOWAIT: Muy utilizado en interfaces de usuario para informar inmediatamente: «Este asiento está siendo reservado en este momento por otro usuario».SKIP LOCKED: Permite a múltiples servidores de procesamiento (background workers) consumir tareas de una tabla de base de datos en paralelo sin bloquearse entre sí.
3. Interbloqueos (Deadlocks) #
Un interbloqueo (Deadlock) es una situación de bloqueo mutuo circular donde dos o más transacciones quedan congeladas indefinidamente porque cada una espera que la otra libere un recurso.
1Transacción 1 Transacción 2 2───────────── ───────────── 31. Bloquea Fila A 🔒 1. Bloquea Fila B 🔒 42. Intenta bloquear Fila B (espera ⏳) 2. Intenta bloquear Fila A (espera ⏳) 5 └─────────── DEADLOCK MUTUO CIRCULAR ───────────┘
¿Cómo gestiona el SGBD los Deadlocks? #
- El motor cuenta con un detector interno de ciclos en el grafo de dependencias (Wait-For Graph).
- Tras superar un umbral (ej. 1 segundo), el SGBD aborta automáticamente una de las transacciones (la «víctima») lanzando un error específico (
40P01en PostgreSQL o1213en MySQL) y permitiendo que la otra transacción continúe.
Buenas Prácticas para Prevenir Deadlocks: #
- Acceder siempre a las tablas y filas en el mismo orden: Si todas las transacciones bloquean siempre las filas ordenadas por su clave primaria (
ORDER BY id), los ciclos de bloqueo son imposibles. - Mantener las transacciones lo más cortas posible: No realizar llamadas HTTP lentas ni procesamiento pesado dentro de un bloque
BEGIN ... COMMIT. - Indexar todas las claves foráneas: Evita que una actualización en una tabla hija escanee y bloquee la tabla padre completa.
Resumen del tema
Conceptos clave #
SELECT ... FOR UPDATE: bloquea exclusivamente las filas leídas para garantizar que no sean alteradas antes de unUPDATE.NOWAIT: aborta con error inmediato si el registro ya está bloqueado por otra transacción activa.SKIP LOCKED: técnica para construir colas de tareas paralelas de alto rendimiento omitiendo filas ocupadas por otros hilos.- Deadlock: bloqueo circular donde dos transacciones se esperan mutuamente; el motor cancela una víctima para desbloquear el sistema.
- Prevención: acceso ordenado y consistente a las tablas y reducción del tiempo de permanencia de las transacciones.
Qué debes recordar #
Usa FOR UPDATE para proteger transacciones de saldo e inventario crítico y SKIP LOCKED para procesar colas de trabajo concurrentes sin colisiones.