Estrategias de concurrencia
Dos estrategias evitan las anomalías de concurrencia. Cada una responde a un balance distinto entre rendimiento y consistencia.
Bloqueo pesimista — prevenir el conflicto
Esta estrategia parte de una premisa: los conflictos entre transacciones son inevitables, por lo tanto deben prevenirse. El sistema bloquea el recurso antes de cualquier operación y garantiza acceso exclusivo mientras esté en uso. En concreto:
| Aspecto | Descripción |
|---|---|
| Acceso Exclusivo | La primera transacción que pide el recurso obtiene el bloqueo. Las demás esperan hasta que se libere. |
| Integridad Garantizada | El sistema evita cualquier anomalía garantizando que nadie más lea o modifique los datos hasta que la transacción termine con COMMIT o ROLLBACK. |
| Impacto operativo | Gana la consistencia, pero se pierde fluidez: las transacciones se ejecutan una detrás de otra para evitar colisiones. |
-- Sesión 1 | -- Sesión 2
BEGIN; |
SELECT stock FROM productos |
WHERE id = 1 FOR UPDATE; |
-- T1 bloquea la fila |
-- stock: 10 |
| BEGIN;
| SELECT stock FROM productos
| WHERE id = 1 FOR UPDATE;
| -- T2 ESPERA hasta que T1 termine
UPDATE productos SET stock = 9 |
WHERE id = 1; |
COMMIT; |
-- T1 libera el lock |
| -- T2 obtiene el lock
| -- stock: 9
| UPDATE productos SET stock = 8
| WHERE id = 1;
| COMMIT;
-- Resultado final: stock = 8 |
Bloqueo optimista — detectar el conflicto
A diferencia del pesimista, este enfoque asume que los conflictos son poco comunes. Deja que todas las transacciones trabajen al mismo tiempo sin restricciones, y solo verifica si hubo cambios justo antes de guardar los datos.
El mecanismo más común es usar una columna de versión:
-- Tabla con columna de versión
CREATE TABLE productos (
id INTEGER PRIMARY KEY,
stock INTEGER NOT NULL,
version INTEGER NOT NULL DEFAULT 1
);
-- Sesión 1 | -- Sesión 2
BEGIN; |
SELECT stock, version |
FROM productos WHERE id = 1; |
-- stock: 10, version: 1 |
| BEGIN;
| SELECT stock, version
| FROM productos WHERE id = 1;
| -- stock: 10, version: 1
UPDATE productos |
SET stock = 9, version = 2 |
WHERE id = 1 AND version = 1; |
-- filas afectadas: 1 |
-- éxito, el dato no cambió |
COMMIT; |
| UPDATE productos
| SET stock = 9, version = 2
| WHERE id = 1 AND version = 1;
| -- filas afectadas: 0
| -- ERROR: el dato ya fue modificado
| -- T2 debe reintentar la operación
El truco está en el WHERE version = 1. Si la fila fue modificada por otra transacción, la versión ya no es 1 y el UPDATE no afecta ninguna fila. La aplicación detecta que no hubo filas actualizadas y sabe que debe reintentar.
Imagina que accedes a un recurso compartido sin reserva previa. Al intentar finalizar tu gestión, el sistema verifica si el estado del recurso cambió mientras lo usabas. Si alguien más lo modificó, tu operación es rechazada y debes reiniciar el proceso.
Comparación: pesimista vs optimista
| Dimensión | Pesimista | Optimista |
|---|---|---|
| Enfoque | Previene el conflicto antes de que ocurra | Detecta el conflicto al momento de escribir |
| Ventaja | Consistencia total Nunca hay datos inconsistentes. Si obtiene el lock, la transacción trabaja sin interferencias. | Alta concurrencia Las transacciones no se bloquean entre sí mientras leen. |
| Desventaja | Baja concurrencia Varias transacciones pueden bloquearse esperando recursos retenidos entre sí. | Reintentos Si hay conflicto, hay que reintentar toda la transacción. En alta contención, los reintentos pueden ser peores que los locks. |
| Cuándo usarlo | Alta contención — muchos usuarios modificando los mismos datos a la vez | Baja contención — los conflictos son poco frecuentes |
| Cuándo evitarlo | Operaciones lentas — mantener un lock mucho tiempo reduce el throughput | Alta contención — los reintentos constantes degradan el rendimiento |
Casos de uso
| Situación | Recomendación |
|---|---|
| Reserva de asientos en un vuelo (mucha gente, mismos asientos) | Pesimista — evitar sobreventas |
| Editar un artículo en un CMS (baja probabilidad de conflicto) | Optimista — mejor experiencia de usuario |
| Transferencia bancaria (dos cuentas, alta integridad) | Pesimista — no puede haber reintentos |
| Likes en una red social (muchos, datos simples) | Optimista — los reintentos son baratos |
Errores frecuentes
Error: El bloqueo optimista no necesita locks
El bloqueo optimista también usa locks, pero muy breves. La diferencia está en la duración, no en la existencia.