Persistencia, transacciones y concurrencia
¿Qué ocurre si un cliente paga una factura, el sistema descuenta su saldo, pero justo antes de marcar la factura como PAGADA se corta la electricidad o falla el servidor? Si al reiniciar el sistema el cliente tiene menos dinero y la factura sigue PENDIENTE, el software ha corrompido la realidad.
Objetivos y conocimientos previos
Integrando todo el Curso II, aprenderás qué garantías distinguen a una persistencia fiable: durabilidad, atomicidad (transacciones), consistencia de invariantes y aislamiento ante concurrencia. Al finalizar, sabrás cómo usar la IA y la documentación oficial para evaluar cualquier tecnología de almacenamiento que te proponga un agente.
Qué significa realmente persistir un dato
Durante la ejecución de un programa, los datos con los que opera de forma inmediata residen en memoria volátil: si el proceso se detiene o se reinicia, desaparecen. Persistir significa registrar el estado en un medio no volátil para que sobreviva en el tiempo.
Sin embargo, «escribir en un archivo o base de datos» no es una operación mágica ni instantánea. Cuando un sistema guarda información que requiere múltiples pasos o recibe peticiones de varias personas a la vez, aparecen tres amenazas lógicas:
- Fallos a mitad de una operación compuesta: se guarda la primera mitad de un cambio y falla la segunda.
- Interferencia por concurrencia: dos procesos leen el mismo dato a la vez y se pisan mutuamente el resultado.
- Pérdida tras confirmación prematura: el sistema responde «éxito» al usuario antes de que el cambio esté realmente asegurado en el almacenamiento persistente.
Transacciones: la garantía de «todo o nada» (Atomicidad)
Muchos cambios de negocio requieren actualizar más de un registro a la vez. Por ejemplo, registrar el pago de una factura implica:
- Insertar un movimiento en la colección
Pagos. - Cambiar el estado de la factura en
FacturasdePENDIENTEaPAGADA.
Si el paso 1 se completa y el paso 2 falla (por un error de disco, de red o una restricción incumplida), el sistema queda en un estado intermedio inválido.
Una transacción agrupa varias operaciones para que el sistema las trate como una única unidad lógica indivisible (atómica):
- Iniciar transacción (Estado inicial íntegro)
- Paso 1: Registrar movimiento de pago
- Paso 2: Marcar factura como PAGADA
- ¿Todos los pasos cumplieron las reglas?Sí (Confirmar / Commit)
- Hacer permanentes ambos cambios
No (Revertir / Rollback)- Deshacer el Paso 1 y volver al estado inicial
- Confirmar (Commit): si todos los pasos terminan con éxito y respetan los invariantes, el nuevo estado se consolida completo.
- Revertir (Rollback): si cualquiera de los pasos falla, el sistema deshace todos los pasos previos de esa transacción, dejando los datos exactamente como estaban antes de empezar.
Concurrencia: cuando el orden del tiempo importa
Supongamos una tarjeta prepago o cuenta con un saldo de 100 EUR. Se lanzan dos cobros simultáneos de 80 EUR (Proceso A y Proceso B) y la regla del negocio exige que el saldo nunca sea menor que 0 EUR.
Observa qué ocurre si ambos procesos leen el saldo antes de que el otro guarde su cambio (condición de carrera del tipo leer-modificar-escribir):
| Instante | Proceso A (Cobro de 80 €) | Proceso B (Cobro de 80 €) | Saldo guardado |
|---|---|---|---|
t1 | Lee saldo: 100 € (>= 80 €, válido). | — | 100 € |
t2 | — | Lee saldo: 100 € (>= 80 €, válido). | 100 € |
t3 | Calcula 100 - 80 = 20 € y guarda 20 €. | — | 20 € |
t4 | — | Calcula 100 - 80 = 20 € y guarda 20 € (o resta 80 € dejando -60 €). | 20 € (cobro perdido) o -60 € (invariante roto) |
Observa la gravedad del fallo:
- Si cada proceso calcula el nuevo saldo en su memoria y sobrescribe el valor, ambos cobros se aprueban pero el saldo queda en
20 €(actualización perdida: se entregaron160 €en servicios cobrando solo80 €). - Si restan sobre el valor sin coordinar la condición previa, el saldo cae a
-60 €(invariante violado).
Para impedirlo, el almacenamiento debe proporcionar aislamiento o control de concurrencia: serializar el acceso al registro afectado, bloquear la fila mientras se decide y actualiza dentro de una transacción, o realizar una actualización condicional atómica (por ejemplo: «descuenta 80 € únicamente si en el instante mismo de escribir el saldo actual sigue siendo mayor o igual a 80 €, y dime si se aplicó»).
Las cuatro garantías clásicas (ACID) como guía de preguntas
En ingeniería de datos, estas propiedades suelen resumirse bajo el acrónimo ACID. No necesitas memorizar la sigla por cultura general, sino usarla como lista de verificación cuando un agente te proponga dónde guardar los datos:
| Propiedad | Pregunta que debes hacer al evaluar la solución |
|---|---|
| Atomicidad (Atomicity) | Si una operación modifica dos colecciones y falla a la mitad, ¿se deshace automáticamente la primera parte? |
| Consistencia (Consistency) | ¿El propio almacenamiento impide guardar datos que violen tipos, claves únicas, integridad referencial o límites, aunque un programa tenga un error? |
| Aislamiento (Isolation) | Si llegan dos solicitudes al mismo milisegundo sobre la última plaza o el mismo saldo, ¿qué mecanismo impide que ambas lean el estado antiguo y aprueben las dos? |
| Durabilidad (Durability) | Una vez que el sistema confirma el éxito al usuario, ¿los datos sobreviven aunque el proceso del servidor se reinicie inmediatamente después? |
Cómo investigar una tecnología de persistencia con IA y fuentes oficiales
Cuando el agente proponga una herramienta concreta (sea una base de datos relacional, documental, un archivo local o un servicio en la nube), aplica el marco de adaptación:
- Declara tus invariantes primero: por ejemplo, «ninguna actividad puede superar sus plazas y cada pago debe actualizar saldo y factura de forma atómica».
- Pregunta qué garantías ofrece la tecnología propuesta: pide al agente que explique cómo resuelve esa herramienta las transacciones y la concurrencia.
- Exige contraste con documentación oficial vigente: pide el enlace o referencia exacta a la documentación de la versión utilizada sobre transacciones y niveles de aislamiento.
- Diseña una prueba de fallo y concurrencia: no te conformes con guardar un registro desde la pantalla; pide probar qué ocurre cuando el segundo paso de una transacción lanza un error forzado.
Practica
Un agente ha implementado un sistema de canje de puntos para clientes. Cuando un cliente canjea un premio de 500 puntos, el código del agente hace tres pasos separados sin transacción:
- Consulta en la base de datos cuántos puntos tiene el cliente.
- Si tiene
500o más, crea un registro en la tablaPremiosEntregados. - Actualiza la tabla
Clientesrestando500 puntosal valor que leyó en el paso 1.
Responde razonadamente:
- ¿Qué ocurre con los puntos y los premios si el paso 2 funciona pero el paso 3 falla porque se cae la conexión con la base de datos?
- ¿Qué ocurre si un cliente que tiene exactamente
500 puntospulsa el botón de canjear desde dos dispositivos al mismo tiempo y ambas solicitudes ejecutan el paso 1 antes de que ninguna llegue al paso 3? - Redacta las condiciones que exigirías al agente para corregir ambos defectos, indicando qué pasos deben ir dentro de una misma transacción y cómo debe coordinarse la lectura y descuento de puntos.
Criterio de comprensión: debes identificar tanto el riesgo de estado inconsistente por fallo parcial (premio entregado sin descontar puntos) como la condición de carrera por doble lectura simultánea (dos premios entregados con saldo para uno solo), exigiendo atomicidad entre la entrega y el descuento y un mecanismo de aislamiento o condición atómica sobre el saldo.
Profundiza con IA
Esta es mi auditoría del sistema de canje de puntos: [tu respuesta]. Evalúa mi explicación. Después, simula que eres un desarrollador que intenta convencerme de que «como el servidor es muy rápido, es casi imposible que dos clics ocurran a la vez». Ayúdame a rebatir ese argumento explicando por qué la latencia entre leer y escribir hace que las condiciones de carrera ocurran en sistemas reales.
Cierre del Curso II y próximo paso
Has recorrido desde el dato aislado hasta las transacciones y la concurrencia. Ahora sabes modelar la memoria de un sistema y exigir garantías sobre su estado.
En el Curso III — Sistemas, Contratos y Comunicación daremos el siguiente paso: cómo dividir un sistema en componentes con responsabilidades claras, cómo definir fronteras de confianza y permisos, y cómo hacer que distintas partes se comuniquen mediante contratos tolerando fallos de red.