Reservas duplicadas en PostgreSQL: transacciones y bloqueos para evitarlo

Publicado el 2026-10-26 por frfrand

Evitar doble reserva y condiciones de carrera con transacciones SQL

Reservas duplicadas en PostgreSQL: transacciones y bloqueos para evitarlo

Queda una sola plaza para un tour. Dos usuarios pulsan «Reservar» casi al mismo tiempo. Si tu backend hace primero un SELECT y después un UPDATE sin protección, ambos pueden ver disponibilidad y vender la misma plaza.

La idea es resolver un problema de datos o despliegue que aparece en aplicaciones reales. Vamos a ver el concepto sin vueltas, un ejemplo de implementación y qué comprobar antes de llevarlo a producción.

Qué hace Transacciones y reservas duplicadas

Las transacciones agrupan operaciones con propiedades ACID y permiten coordinar acceso concurrente. Un bloqueo de fila FOR UPDATE, una actualización condicional atómica o una restricción de unicidad pueden resolver distintos modelos. Lo correcto depende de la estructura de cupos y pagos.

No alcanza con repetir una receta si no entendés quién lee los datos, desde qué proceso y con qué permisos. En una aplicación con reservas, facturas o usuarios, una condición de carrera o una política de acceso mal hecha puede ser más grave que una API lenta.

Un ejemplo concreto

BEGIN;
SELECT plazas_disponibles
FROM horarios
WHERE id = 42
FOR UPDATE;
-- Si plazas_disponibles >= 1, descontar y crear reserva
UPDATE horarios
SET plazas_disponibles = plazas_disponibles - 1
WHERE id = 42 AND plazas_disponibles >= 1;
-- Comprobar ROW_COUNT / RETURNING antes de confirmar
COMMIT;

Los nombres, tablas y claves de este ejemplo son ilustrativos. Probalo primero en una base o entorno de ensayo y adaptá permisos, índices y versiones. Cuando haya operaciones de escritura, no ejecutes consultas de muestra sobre datos de clientes sin revisar qué modifican.

Paso a paso

  1. Defina la regla de negocio: plazas máximas, reservas pendientes, expiración y pagos.
  2. Guarde disponibilidad y reservas con restricciones que impidan estados imposibles.
  3. Use una transacción corta que bloquee o actualice de forma condicional el recurso.
  4. Compruebe el resultado del UPDATE; si no quedan plazas, responda un error de negocio claro.
  5. Pruebe dos peticiones concurrentes y verifique que solo una consume la última plaza.

Al final no se quede con «el SQL no dio error». Compruebe el efecto real desde la API y con pruebas de concurrencia o permisos según corresponda. En bases de datos hay errores que solo aparecen cuando dos usuarios hacen algo a la vez.

Ejemplo de proyecto de trabajo

En la web de tours, el cliente A y el B eligen la última plaza. Con la fila del horario bloqueada en una transacción, el segundo espera y al reanudar ve la disponibilidad ya actualizada.

Ese escenario ayuda a distinguir rendimiento de consistencia. Acelerar una consulta no sirve si permite crear dos reservas para una sola plaza, ni una base enorme arregla que el backend permita consultar datos de otro cliente.

El error típico

El ejemplo es un esquema simplificado; no haga pagos externos mientras mantenga una transacción abierta. Separe reserva provisional y confirmación por webhook usando idempotencia.

También conviene tener un plan de recuperación. Antes de tocar esquema, usuarios o políticas, guarda una copia verificable o migración reversible y comprueba que la aplicación pueda seguir funcionando durante el cambio.

¿Cómo lo resolvería con ArduMaker?

Un backend Django o FastAPI en ArduMaker puede utilizar PostgreSQL para esta lógica. La integridad se diseña en la base y aplicación, no se obtiene automáticamente por el proveedor VPS.

ArduMaker te permite desplegar servicios desde Git y trabajar con bases y procesos dentro del VPS. El panel no reemplaza la lógica de tu aplicación: transacciones, permisos y validaciones deben quedar correctamente diseñados en el código y la base de datos.

Tres comprobaciones antes de publicar

Integridad: si una petición se repite o falla a mitad de camino, ¿los datos terminan en un estado válido?

Seguridad: ¿un usuario autenticado puede acceder solo a su información, y la API utiliza una identidad de base con permisos mínimos?

Recuperación: ¿sabes restaurar los datos y revertir la versión de código compatible si una actualización sale mal?

Si puedes responder a esas tres preguntas con pruebas, tu backend está bastante mejor preparado que cuando solo miraste si el endpoint devolvía 200.

Recursos para profundizar

Para cerrar: elegí la solución más simple que permita mantener datos correctos, seguros y recuperables. El rendimiento viene después de medir.

  • PostgreSQL
  • Tutorial
  • ArduMaker

En ArduMaker

  • PostgreSQL: Instalás PostgreSQL y administrás bases, usuarios y permisos sin línea de comandos.

Seguir leyendo

Todos los artículos · Planes de VPS