El dinero no se duplica · Episodio 4 de 7

Dos Bizum a la vez

Laura lleva 1.200 € de Bizum hoy. Desde el móvil envía 600 € y, en el mismo segundo, desde la tableta, 500 €. Las dos peticiones miran el límite, las dos ven 1.200 € y las dos pasan: 2.300 €.

Concepto: niveles de aislamiento; lost update y write skew~12 min

El punto de partida

En Las áreas del banco, el límite diario de Laura se convirtió en un agregado: el grupo de datos que se cambia de una vez para que la regla de los 2.000 € se cumpla siempre. La definición prometía algo concreto: mientras se cambia, nadie más puede tocarlo.

Esa promesa no la cumple el diagrama. La cumple la base de datos, con sus transacciones, y hasta dónde la cumple depende de una opción que casi nadie mira: el nivel de aislamiento.

Leer, comprobar, escribir

Para cumplir la regla, cada Bizum hace tres cosas: lee cuánto lleva Laura hoy, comprueba que el nuevo cabe y escribe. Si dos Bizum lo hacen a la vez, sus pasos se entrelazan: los dos leen antes de que ninguno escriba.

Que eso pase no es raro. Laura tiene dos dispositivos vinculados; la app reintenta; Operaciones corre en varios servidores. «A la vez» es cada día.

En la simulación, cada transacción tiene su línea de tiempo: T1 arriba, T2 abajo. En medio está el dato que comparten. Elige cómo se guarda el dato y qué nivel de aislamiento usa la base de datos, y lanza las dos transacciones. Prueba las seis combinaciones.

Qué ha pasado

El entrelazado es siempre el mismo. Lo que cambia es qué deja pasar la base de datos, y depende de dos cosas a la vez:

La lección incómoda es que el mismo nivel de aislamiento protege un diseño y no otro. Guardar los Bizum como filas que nunca se modifican es un buen diseño (no se pierde historia), y precisamente por eso snapshot deja de bastar.

El recibo y el Bizum

El día de cobro, el recibo de la luz (90 €) llega a la cuenta de Laura justo cuando ella envía un Bizum de 50 €. Tiene 100 € disponibles: cabe uno de los dos, no los dos. Según las reglas de las domiciliaciones, si el saldo no cubre el recibo, se devuelve.

Elige el caso «Recibo y Bizum» en la simulación. El saldo de una cuenta es la suma de sus movimientos, y los movimientos nunca se modifican: es exactamente el caso de las filas. Con snapshot, los dos pasan y la cuenta queda en −40 €. Con un saldo guardado y read committed, es peor: el saldo dice 50 € y han salido 140 €.

El nivel más estricto no es gratis

Si serializable lo arregla todo, ¿por qué no usarlo siempre? Porque aborta más transacciones, y cada una hay que reintentarla. Con mucho tráfico sobre los mismos datos, los reintentos se acumulan. Y muchas bases de datos no lo usan por defecto: lo normal es read committed. Hay que saber qué nivel se tiene, y qué anomalías deja pasar con la forma en que se guardan los datos.

Hay otra salida: no dejar que dos transacciones lleguen a leer a la vez. Es decir, bloquear. Pero bloquear tiene su propio precio, y lo veremos con la cuenta de casa un día 1 de mes.

Para llevarse