Explica ACID — y da un ejemplo real de una transacción que se rompería si se violara cada propiedad
Cualquiera puede recitar la sigla; un ingeniero senior puede producir una transacción concreta y mostrar exactamente cómo se rompe si se elimina la Atomicidad, la Consistencia, el Aislamiento o la Durabilidad.
APRENDE HACIENDOPon a prueba tu intuición3 pasos
Explica ACID — y da un ejemplo real de una transacción que se rompería si se violara cada propiedad
Usa los ejemplos y la explicación de la lección para comprobar tu idea.
Reflexión personal. No se envía a ningún servicio de IA.#ACID, rompiendo una propiedad a la vez
ACID son Atomicidad, Consistencia, Aislamiento y Durabilidad — cuatro garantías que una base de datos transaccional promete para cada transacción. La forma más rápida de entender (y de explicar) cada una es describir el bug exacto que obtendrías si la base de datos la abandonara silenciosamente, usando el mismo ejemplo de siempre: transferir $100 de la cuenta A a la cuenta B.
CREATE TABLE accounts (account_id INTEGER PRIMARY KEY,balance_cents INTEGER NOT NULL CHECK (balance_cents >= 0));
#Atomicidad — todos los pasos ocurren, o ninguno
Una transferencia en realidad son dos escrituras: debitar A, acreditar B. La atomicidad garantiza que la base de datos las trate como una unidad indivisible — ambas ocurren o ninguna ocurre, incluso si el proceso se cae entre medio.
BEGIN;UPDATE accounts SET balance_cents = balance_cents - 10000 WHERE account_id = 'A';UPDATE accounts SET balance_cents = balance_cents + 10000 WHERE account_id = 'B';COMMIT;
Si se violara la atomicidad, la base de datos (o una aplicación descuidada) podría ejecutar el primer UPDATE, caerse antes del segundo, y dejar el dinero debitado de A pero nunca acreditado en B — $100 simplemente desaparecen. Este es exactamente el bug que obtienes al envolver las dos sentencias en llamadas separadas con auto-commit en lugar de una sola transacción: un crash entre las dos llamadas deja al sistema en un estado que nunca fue un paso intermedio válido de ninguna transferencia correcta, porque una transferencia correcta o no ocurre o ocurre completamente. Las bases de datos garantizan la atomicidad con un write-ahead log (WAL): antes de aplicar los cambios, el cambio previsto se registra de forma durable, así que durante la recuperación de un crash la base de datos puede terminar de reproducir una transacción confirmada o revertir una no confirmada, pero nunca dejarla a medias.
#Consistencia — cada transacción deja intactos los invariantes declarados
La consistencia significa que una transacción solo puede mover la base de datos de un estado que satisface todas las reglas declaradas (restricciones, claves foráneas, triggers) a otro estado que también las satisface — es el motor de base de datos haciendo cumplir tus invariantes, no una garantía de que tu lógica de negocio esté libre de bugs.
-- La restricción CHECK de arriba (balance_cents >= 0) es exactamente esto:-- un invariante que la base de datos se niega a dejar violar a-- cualquier transacción.BEGIN;UPDATE accounts SET balance_cents = balance_cents - 10000 WHERE account_id = 'A';-- Si A solo tenía $50, este UPDATE ahora viola balance_cents >= 0-- y toda la transacción es rechazada — nada se confirma.COMMIT;
Si se violara la consistencia, la base de datos dejaría que esa transacción se confirmara de todas formas, dejando la cuenta A con un saldo negativo — un estado que debería ser estructuralmente imposible dada la restricción que declaraste. Nota la diferencia con la atomicidad: la atomicidad trata sobre que la transacción se complete entera o no se complete en absoluto; la consistencia trata sobre que el estado resultante obedezca las reglas que le dijiste a la base de datos que hiciera cumplir, sean las que sean.
#Aislamiento — las transacciones concurrentes no corrompen la visión de las otras
El aislamiento garantiza que las transacciones concurrentes se comporten (en algún grado configurable) como si se hubieran ejecutado una tras otra, y no entrelazadas de formas que produzcan resultados imposibles.
-- Transacción 1 Transacción 2BEGIN; BEGIN;SELECT balance_cents FROM accounts SELECT balance_cents FROM accountsWHERE account_id = 'A'; WHERE account_id = 'A';-- ambas leen 10000 (es decir, $100.00)-- T1 calcula 10000 - 3000 = 7000 -- T2 calcula 10000 - 5000 = 5000UPDATE accounts SET balance_cents = 7000WHERE account_id = 'A';COMMIT;UPDATE accounts SET balance_cents = 5000WHERE account_id = 'A';COMMIT;-- Saldo final: 5000 — el retiro de $30 de T1 se perdió silenciosamente.
Esta es la clásica anomalía de actualización perdida: ambas transacciones leyeron el mismo saldo inicial, calcularon su propio saldo nuevo "correcto" en código de aplicación, y la segunda escritura pisó a la primera — $30 desaparecieron sin que se levantara ningún error en ningún lado. Si el aislamiento estuviera completamente ausente, también verías lecturas sucias (leer cambios no confirmados de otra transacción) y otras anomalías. La solución es un nivel de aislamiento más estricto (SERIALIZABLE, que forzaría a una de estas transacciones a fallar y reintentar) o bloqueo explícito:
BEGIN;SELECT balance_cents FROM accounts WHERE account_id = 'A' FOR UPDATE;-- FOR UPDATE bloquea esta fila; el SELECT ... FOR UPDATE de la-- Transacción 2 sobre la misma fila ahora se bloquea hasta que la-- Transacción 1 confirme o revierta.UPDATE accounts SET balance_cents = balance_cents - 3000 WHERE account_id = 'A';COMMIT;
#Durabilidad — una vez confirmada, un crash no puede deshacerla
La durabilidad garantiza que, una vez que la base de datos le devuelve al cliente "commit exitoso", los efectos de esa transacción sobreviven a cualquier crash posterior — corte de energía, proceso terminado, reinicio del controlador de disco.
Si se violara la durabilidad — digamos, la base de datos confirmó el commit apenas la escritura llegó a un buffer en memoria o a la caché de páginas del sistema operativo, sin llamar a fsync para forzarla al disco físico — entonces un crash unos segundos después de que el cliente recibiera "éxito" podría revertir la base de datos a un punto anterior a la transferencia, aunque al cliente se le dijo que había tenido éxito y puede que ya le haya avisado al usuario que su transferencia se realizó. Las bases de datos garantizan la durabilidad forzando el registro del write-ahead log a almacenamiento persistente (mediante fsync o equivalente) antes de confirmar el commit, y los sistemas de producción agregan replicación síncrona a un segundo nodo para que la durabilidad sobreviva incluso a la pérdida de una máquina entera, no solo a la caída de un proceso.
#Uniendo todo
| Propiedad | Garantiza | Qué se rompe sin ella | Se hace cumplir con |
|---|---|---|---|
| Atomicidad | Ejecución todo-o-nada | Transferencias a medio terminar; dinero debitado pero nunca acreditado | Write-ahead log + rollback en la recuperación de crash |
| Consistencia | Los invariantes declarados siempre se cumplen | Saldos negativos, claves foráneas huérfanas | Restricciones, triggers, claves foráneas |
| Aislamiento | Las transacciones concurrentes no se corrompen entre sí | Actualizaciones perdidas, lecturas sucias, lecturas no repetibles | Bloqueo (2PL) o MVCC + niveles de aislamiento |
| Durabilidad | Los datos confirmados sobreviven a los crashes | Transacciones confirmadas que desaparecen silenciosamente | WAL con fsync + replicación |
#Ponte a prueba
🧠 Check your understanding
0/3 · 0/3 answered1. Dos transacciones concurrentes leen el mismo saldo de $100, cada una resta un monto distinto de forma independiente, y escriben su resultado — la segunda escritura sobrescribe por completo el cambio de la primera. ¿Qué propiedad ACID se violó?
2. Una base de datos confirma un commit al cliente pero solo había escrito el cambio en la caché de páginas del sistema operativo, sin hacer fsync a disco. La máquina pierde energía un segundo después y el cambio desaparece. ¿Qué propiedad falló?
3. Una restricción CHECK impide que un UPDATE deje el saldo de una cuenta en negativo, provocando que toda la transacción se revierta. ¿Qué propiedad se está haciendo cumplir?