Entendiendo las Transacciones de Base de Datos
Cuando un usuario realiza un pedido en tu plataforma, varias cosas suceden simultáneamente: el inventario disminuye, se crea un registro de pago y se guarda una entrada de pedido. Si el servidor falla a mitad del proceso, podrías terminar con un cliente cobrado y sin pedido. Las transacciones de base de datos existen específicamente para prevenir ese tipo de fallo parcial.
Este artículo cubre qué son las transacciones de base de datos, cómo las propiedades ACID garantizan la fiabilidad, cómo los niveles de aislamiento de transacciones controlan el acceso concurrente, y cómo las bases de datos modernas utilizan MVCC para hacer que todo esto funcione de manera eficiente.
Puntos Clave
- Una transacción de base de datos agrupa múltiples operaciones en una única unidad de trabajo — o todas tienen éxito o todas se revierten.
- Las propiedades ACID (Atomicidad, Consistencia, Aislamiento, Durabilidad) definen las garantías de fiabilidad que proporcionan las transacciones.
- SQL define cuatro niveles de aislamiento, pero el comportamiento real varía significativamente entre motores de bases de datos como PostgreSQL, MySQL y SQLite.
- MVCC permite que las bases de datos modernas manejen lecturas y escrituras concurrentes de manera eficiente manteniendo múltiples versiones de filas en lugar de depender de bloqueos pesados.
¿Qué es una Transacción de Base de Datos?
Una transacción de base de datos es una secuencia de operaciones tratadas como una única unidad de trabajo. O todas las operaciones tienen éxito y los cambios se confirman, o algo falla y todo se revierte al estado anterior.
En SQL, una transacción básica se ve así:
BEGIN;
UPDATE accounts SET balance = balance - 500 WHERE id = 1;
UPDATE accounts SET balance = balance + 500 WHERE id = 2;
COMMIT;
Si algo falla entre BEGIN y COMMIT, un ROLLBACK restaura la base de datos a su estado antes de que comenzara la transacción. La mayoría de las bases de datos también soportan SAVEPOINT para reversiones parciales dentro de una transacción.
Propiedades ACID: Lo Que Realmente Significan
ACID es el conjunto de garantías que hacen que las transacciones sean fiables:
- Atomicidad — Todos los pasos tienen éxito, o ninguno lo hace. Sin actualizaciones parciales.
- Consistencia — La base de datos pasa de un estado válido a otro. Se aplican restricciones y reglas.
- Aislamiento — Las transacciones concurrentes no interfieren entre sí.
- Durabilidad — Una vez confirmados, los cambios sobreviven a fallos del sistema. Esto se implementa típicamente mediante registros de escritura anticipada (WAL, por sus siglas en inglés).
El cumplimiento de ACID tiene un costo de rendimiento. Algunos sistemas te permiten intercambiar garantías estrictas por velocidad, por lo que entender estas propiedades es importante al diseñar tu capa de datos.
Niveles de Aislamiento de Transacciones Explicados
El aislamiento es la más matizada de las cuatro propiedades ACID. SQL define cuatro niveles de aislamiento de transacciones estándar, cada uno permitiendo diferentes compensaciones entre consistencia y concurrencia:
| Nivel de Aislamiento | Lecturas Sucias | Lecturas No Repetibles | Lecturas Fantasma |
|---|---|---|---|
| READ UNCOMMITTED | Posibles | Posibles | Posibles |
| READ COMMITTED | Prevenidas | Posibles | Posibles |
| REPEATABLE READ | Prevenidas | Prevenidas | Posibles |
| SERIALIZABLE | Prevenidas | Prevenidas | Prevenidas |
Importante: El comportamiento real varía según el motor de base de datos.
- PostgreSQL no implementa
READ UNCOMMITTED— lo actualiza silenciosamente aREAD COMMITTED. Su valor predeterminado esREAD COMMITTEDcomo se documenta en la guía oficial de niveles de aislamiento. - MySQL (InnoDB) tiene como predeterminado
REPEATABLE READ. Utiliza bloqueos de brecha en ciertos casos para reducir lecturas fantasma, pero el comportamiento depende del nivel de aislamiento y el patrón de consulta como se describe en la documentación de aislamiento de InnoDB. - SQLite utiliza un modelo de escritor único, lo que significa que solo una transacción de escritura puede ejecutarse a la vez. Soporta modos de transacción
DEFERRED,IMMEDIATEyEXCLUSIVEen lugar de los niveles de aislamiento estándar, como se describe en la documentación de transacciones de SQLite.
No asumas un comportamiento idéntico entre bases de datos. Siempre verifica la documentación de tu motor específico.
Discover how at OpenReplay.com.
Cómo MVCC Hace Práctico el Aislamiento
La mayoría de las bases de datos relacionales modernas — incluyendo PostgreSQL y MySQL (InnoDB) — implementan el aislamiento mediante Control de Concurrencia Multiversión (MVCC) en lugar de bloqueos simples.
Con MVCC, las consultas ven una instantánea consistente de los datos, pero si esa instantánea se toma por sentencia o por transacción depende del nivel de aislamiento y del motor de base de datos. Los escritores crean nuevas versiones de filas en lugar de sobrescribirlas. Los lectores no bloquean a los escritores, y los escritores no bloquean a los lectores.
Por esto PostgreSQL puede servir cargas de trabajo con muchas lecturas sin que los lectores esperen constantemente por bloqueos. La compensación es que las versiones antiguas de filas se acumulan y deben limpiarse — en PostgreSQL, esto lo maneja el proceso VACUUM.
MVCC es lo que hace práctico REPEATABLE READ y el aislamiento de instantáneas a escala.
Transacciones en Diferentes Sistemas
No todas las bases de datos manejan las transacciones de la misma manera:
- MySQL (InnoDB) soporta transacciones ACID completas. El motor MyISAM más antiguo no lo hace.
- PostgreSQL tiene MVCC robusto y soporta aislamiento
SERIALIZABLEcon verdaderas garantías de serialización. - SQLite cumple completamente con ACID pero serializa todas las escrituras, haciéndolo inadecuado para cargas de trabajo de escritura de alta concurrencia.
- MongoDB agregó transacciones multi-documento en la versión 4.0, pero conllevan más sobrecarga que en las bases de datos relacionales tradicionales y es mejor usarlas selectivamente.
Pautas Prácticas para Usar Transacciones
- Mantén las transacciones cortas. Las transacciones de larga duración mantienen bloqueos o retienen instantáneas MVCC antiguas, lo que degrada el rendimiento.
- No envuelvas consultas de solo lectura en transacciones innecesariamente — especialmente en APIs de alto tráfico.
- Maneja los errores explícitamente. Siempre asegúrate de que ocurra un
ROLLBACKen caso de fallo, ya sea que escribas SQL puro o uses un ORM. - Elige tu nivel de aislamiento deliberadamente.
READ COMMITTEDes un predeterminado razonable para la mayoría de las aplicaciones web. UsaSERIALIZABLEsolo cuando la corrección lo demande, y prueba el impacto en el rendimiento.
Conclusión
Las transacciones de base de datos te dan una forma fiable de mantener los datos consistentes a través de múltiples operaciones. Entender las propiedades ACID te dice con qué garantías estás trabajando. Conocer tus niveles de aislamiento y cómo tu base de datos específica implementa MVCC te dice qué cuestan realmente esas garantías — y dónde viven los casos límite. Ese conocimiento es lo que separa a los desarrolladores que usan transacciones de los desarrolladores que las usan bien.
Preguntas Frecuentes
Usa SERIALIZABLE cuando tu aplicación requiera garantías estrictas de corrección, como cálculos financieros o gestión de inventario donde las transacciones concurrentes no deben producir resultados conflictivos. Para la mayoría de las aplicaciones web, READ COMMITTED ofrece un buen equilibrio entre consistencia y rendimiento. Siempre haz pruebas de rendimiento de SERIALIZABLE en tu entorno, ya que puede reducir la concurrencia y llevar a reintentos de transacciones dependiendo del motor de base de datos.
La mayoría de las bases de datos envuelven automáticamente cada sentencia SQL individual en una transacción implícita, por lo que un solo INSERT o UPDATE ya es atómico. Las transacciones explícitas se vuelven necesarias cuando necesitas agrupar múltiples sentencias en una unidad de trabajo, asegurando que todas tengan éxito o todas fallen juntas. Envolver una sentencia solitaria en BEGIN y COMMIT agrega sobrecarga sin beneficio significativo.
Siempre usa bloques try-catch o equivalentes de manejo de errores alrededor de tu lógica de transacciones. Si alguna operación dentro de la transacción lanza un error, ejecuta un ROLLBACK para deshacer todos los cambios. Muchos ORMs y bibliotecas de bases de datos proporcionan ayudantes de transacciones incorporados que automáticamente revierten en caso de excepciones. Evita suprimir errores silenciosamente, ya que esto puede dejar tus datos en un estado inconsistente.
El bloqueo tradicional puede causar que lectores y escritores se bloqueen entre sí con más frecuencia, lo que limita la concurrencia. MVCC evita esto manteniendo múltiples versiones de cada fila para que los lectores accedan a una instantánea consistente sin esperar a los escritores. La compensación es que las versiones antiguas de filas deben limpiarse periódicamente, como PostgreSQL hace con su proceso VACUUM. MVCC generalmente proporciona mejor rendimiento para cargas de trabajo con muchas lecturas.
Gain control over your UX
See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay. — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.