Recorre los niveles de aislamiento de transacciones — de Read Uncommitted a Serializable — y la anomalía que resuelve cada uno
Los niveles de aislamiento son una perilla que intercambia consistencia por concurrencia — aprende qué anomalía cierra cada nivel y qué te cuesta en throughput.
APRENDE HACIENDOPon a prueba tu intuición3 pasos
Recorre los niveles de aislamiento de transacciones — de Read Uncommitted a Serializable — y la anomalía que resuelve cada uno
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.#Por qué existen los niveles de aislamiento
Se supone que una transacción de base de datos se comporta como si se ejecutara sola, aunque en realidad decenas de transacciones se están ejecutando al mismo tiempo sobre las mismas filas. El aislamiento total — literalmente ejecutar las transacciones una por una — se llama serializabilidad, y es la garantía más segura posible. También suele ser demasiado lenta, porque obliga a la base de datos a serializar trabajo que en otras condiciones podría correr en paralelo.
Los niveles de aislamiento son una perilla que intercambia parte de esa seguridad por throughput. El estándar SQL define cuatro niveles — Read Uncommitted, Read Committed, Repeatable Read y Serializable — y cada uno cierra una categoría específica de anomalía de concurrencia. Lo que realmente pregunta el entrevistador es: ¿entiendes qué puede salir mal cuando las transacciones se solapan, y qué nivel cierra qué agujero?
#Las tres anomalías clásicas
- Lectura sucia (dirty read) — la transacción B lee una fila que la transacción A modificó pero aún no confirmó (commit). Si A hace rollback, B leyó datos que oficialmente nunca existieron.
- Lectura no repetible (non-repeatable read) — la transacción B lee la misma fila dos veces dentro de una sola transacción y obtiene dos valores distintos, porque A confirmó un cambio sobre esa fila en el medio.
- Lectura fantasma (phantom read) — la transacción B ejecuta la misma consulta por rango dos veces y obtiene un conjunto de filas distinto la segunda vez, porque A insertó o borró una fila que cumple el predicado de la consulta.
| Nivel de aislamiento | Lectura sucia | Lectura no repetible | Lectura fantasma |
|---|---|---|---|
| Read Uncommitted | Posible | Posible | Posible |
| Read Committed | Evitada | Posible | Posible |
| Repeatable Read | Evitada | Evitada | Posible (estándar) / Evitada (InnoDB) |
| Serializable | Evitada | Evitada | Evitada |
#Lectura sucia, en SQL
-- Sesión ABEGIN;UPDATE cuentas SET saldo = saldo - 100 WHERE id = 1;-- todavía sin confirmar-- Sesión B, corriendo en READ UNCOMMITTEDBEGIN;SELECT saldo FROM cuentas WHERE id = 1; -- ve el saldo ya debitadoCOMMIT;-- Sesión AROLLBACK; -- el débito nunca ocurrió, pero B ya actuó sobre él
Si la sesión B usó ese saldo para aprobar un retiro, ahora entregaste dinero por una operación que fue deshecha. Casi nadie corre cargas de producción en Read Uncommitted precisamente por esto — se usa sobre todo en consultas analíticas que aceptan a propósito números desactualizados o inconsistentes a cambio de cero bloqueo.
#Lectura no repetible, en SQL
-- Sesión A, en READ COMMITTED (default de Postgres/Oracle)BEGIN;SELECT saldo FROM cuentas WHERE id = 1; -- devuelve 500-- Sesión BBEGIN;UPDATE cuentas SET saldo = 300 WHERE id = 1;COMMIT;-- Sesión A, misma transacciónSELECT saldo FROM cuentas WHERE id = 1; -- devuelve 300, misma consulta, otra respuestaCOMMIT;
Read Committed solo promete que nunca vas a ver datos sin confirmar — no dice nada sobre ver el mismo dato dos veces. Un reporte que lee un valor al inicio de una transacción y lo vuelve a leer más tarde, esperando consistencia, se quema justo aquí.
#Lectura fantasma, en SQL
-- Sesión A, en REPEATABLE READ (semántica estándar)BEGIN;SELECT COUNT(*) FROM pedidos WHERE estado = 'pendiente'; -- devuelve 10-- Sesión BBEGIN;INSERT INTO pedidos (estado, monto) VALUES ('pendiente', 42.00);COMMIT;-- Sesión A, misma transacciónSELECT COUNT(*) FROM pedidos WHERE estado = 'pendiente'; -- devuelve 11COMMIT;
Repeatable Read bloquea (o toma una instantánea de) las filas que ya leyó, así que la lectura no repetible tipo saldo queda resuelta. Pero no hace nada para impedir que se inserte una fila completamente nueva que cumpla el predicado — esa fila nunca estuvo bloqueada porque todavía no existía.
#Cómo lo implementan realmente las bases de datos
Aparecen dos familias de mecanismos por debajo, y a los entrevistadores les gusta que sepas nombrarlas:
- Basado en locks (2PL — locking en dos fases). Los lectores toman locks compartidos, los escritores toman locks exclusivos, y Serializable añade locks de predicado/rango para frenar los fantasmas. Es correcto, pero puede generar mucho bloqueo y deadlocks.
- MVCC (control de concurrencia multiversión). Postgres, MySQL/InnoDB y Oracle mantienen varias versiones de cada fila y le entregan a cada transacción una instantánea consistente, así los lectores nunca bloquean a los escritores. Serializable bajo MVCC (Postgres lo llama SSI, serializable snapshot isolation) detecta patrones conflictivos de lecturas y escrituras después del hecho y aborta una de las transacciones en lugar de bloquear de entrada.
#Elegir un nivel en la práctica
La mayoría de los equipos usa Read Committed por defecto para cargas OLTP — es el default de Postgres y Oracle, evita la anomalía (lecturas sucias) que es genuinamente peligrosa para lógica relacionada con dinero, y no paga el costo de garantías que la mayoría de los endpoints no necesitan. Recurre a Repeatable Read cuando una sola transacción hace múltiples lecturas del mismo dato y necesita que coincidan (un generador de reportes, un cálculo de varios pasos). Recurre a Serializable cuando la corrección realmente depende de que las transacciones no se entrelacen en absoluto — contadores de inventario, prevención de doble reserva, cualquier caso donde un fantasma o un write skew permitiría que dos transacciones crean, cada una, que hicieron la última edición de forma segura.
🧠 Check your understanding
0/1 · 0/1 answered1. ¿Qué nivel de aislamiento sigue permitiendo lecturas fantasma según el estándar SQL?