PostgreSQL
Integración de PostgreSQL con aplicaciones
Integración de PostgreSQL con aplicaciones mediante drivers, pools, transacciones, timeouts, cancelación, errores SQLSTATE, tipos e idempotencia.
- Última actualización
- Actualizada
- Nivel
- Aplicación
PostgreSQL
Integración de PostgreSQL con aplicaciones mediante drivers, pools, transacciones, timeouts, cancelación, errores SQLSTATE, tipos e idempotencia.
La integración con PostgreSQL no termina al ejecutar SQL. El contrato incluye conexiones, tipos, transacciones, errores, cancelación, idempotencia, observabilidad y cierre ordenado del proceso.
Una operación de aplicación atraviesa varias fronteras:
request validado
→ obtener conexión
→ establecer contexto seguro
→ ejecutar SQL parametrizado
→ mapear tipos y errores
→ confirmar o revertir
→ liberar conexión
→ responderCada frontera puede fallar de forma distinta. Tratar todo como “database error” impide reaccionar correctamente.
El driver implementa el protocolo de PostgreSQL y gestiona:
La aplicación debe conocer qué convierte automáticamente y qué entrega como string o buffer.
Usa un pool limitado, no una conexión por consulta. Mide:
Una operación puede agotar su timeout antes de tocar PostgreSQL.
SELECT id, total_amount
FROM orders
WHERE business_id = $1
AND id = $2;Los valores se envían separados. Identifiers dinámicos requieren whitelist.
Casts explícitos ayudan con NULL o arrays:
WHERE id = ANY($1::uuid[])Puede exceder el entero seguro de JavaScript; muchos drivers lo entregan como string.
Debe preservarse como decimal/string o librería decimal; convertirlo a floating point puede perder precisión.
Representa un instante. Convierte para presentación en la zona apropiada.
Representa una fecha civil, no un instante UTC.
Valida runtime; el tipo estático no garantiza shape.
Debe reflejarse en tipos y lógica del dominio.
El mapping forma parte del contrato del repositorio.
Todas las sentencias usan el mismo client:
acquire
→ BEGIN
→ queries
→ COMMIT
→ releaseAnte error:
ROLLBACK
→ clasificar
→ releaseNunca devuelvas al pool una conexión con transacción abierta o abortada.
Un helper debe:
SET LOCAL de tenant/timeouts.No debe ocultar side effects externos dentro del callback.
Mapea códigos estables:
23505 → conflicto de unicidad
23503 → referencia inválida
23514 → check violation
40001 → serialization failure
40P01 → deadlock
57014 → canceled/timeoutEl nombre de constraint puede ayudar a mapear a un error de dominio. No dependas únicamente del texto humano del mensaje.
Reintenta únicamente errores transitorios conocidos y con límite/backoff. Debe repetirse toda la transacción porque las lecturas anteriores pertenecían al intento abortado.
Una pérdida de conexión cerca de COMMIT produce resultado incierto. La operación necesita idempotency key o reconciliación, no un retry ciego.
Ejemplo:
INSERT INTO idempotency_keys(key, operation, response)
VALUES ($1, 'create_order', NULL)
ON CONFLICT (key) DO NOTHING
RETURNING key;La key debe estar scopeada por actor/tenant y proteger el mismo resultado. Después, cambio de negocio y respuesta durable se coordinan en una transacción.
Configura capas coherentes:
lock_timeout.statement_timeout.El timeout externo debería dejar margen para cancelar y limpiar la query.
Cuando el cliente abandona la request, cancela la query si el driver lo soporta. Aun cancelada, la conexión puede necesitar consumir respuesta o ser descartada. No la liberes como sana sin conocer el estado.
Para millones de filas:
cursor/stream
→ lotes
→ backpressure
→ cancelación
→ cierreMantiene client y a menudo transacción durante más tiempo. Limita duración y no mezcles exports enormes con el pool de tráfico crítico.
Prefiere:
COPY.unnest cuidadosamente tipados.Evita una query por elemento. Define tamaño de lote según límites de parámetros, memoria, WAL y atomicidad.
Un repositorio debe exponer operaciones del dominio, no SQL arbitrario:
reserveInventory(...)
findOrderForUpdate(...)
listOrdersPage(...)Debe documentar:
Registra sin secretos:
No uses SQL completo con valores como label de métricas.
SELECT 1 prueba conexión básica. Readiness puede comprobar que:
Evita checks que generen carga significativa.
Un shutdown abrupto puede dejar COMMIT incierto y jobs duplicados.
Los mocks son útiles para lógica externa, no para demostrar semántica SQL.
PostgreSQL con Node.js y TypeScript convierte estos contratos en código explícito y verificable.