Definición
La concurrencia es que varias cosas ocurran a la vez en un sistema: dos usuarios guardando el mismo registro, un proceso periódico ejecutándose mientras alguien usa la aplicación, diez peticiones tocando la misma tabla.
Es la situación normal en cuanto un sistema tiene más de un usuario. Y es la fuente de los errores más desagradables que existen, por una razón: dependen del momento exacto. No se reproducen a voluntad, no aparecen en las pruebas y ocurren una vez cada mil.
Una precisión de vocabulario que ayuda: concurrencia es gestionar varias cosas en marcha a la vez; paralelismo es ejecutarlas literalmente al mismo tiempo. Los problemas que siguen aparecen con la primera, aunque no haya la segunda.
La condición de carrera
Es el patrón central, y casi siempre tiene la misma forma: leer, modificar, escribir.
Un ejemplo con números. Quedan 10 unidades de un producto. Dos pedidos de 6 unidades llegan a la vez:
- El pedido A lee: hay 10. Suficiente.
- El pedido B lee: hay 10. Suficiente.
- A escribe: quedan 4.
- B escribe: quedan 4.
Se han vendido 12 unidades de 10 y el stock dice 4. Ninguno de los dos hizo nada mal por separado. El fallo está en que entre leer y escribir pasó algo.
El mismo patrón produce números de factura duplicados, dobles cobros y contadores que pierden incrementos.
Cómo se resuelve
Dejar que lo haga la base de datos. La opción más segura y la más ignorada. En lugar de leer, calcular y escribir, se escribe una operación que actualiza en un solo paso, con la condición incluida: descontar stock solo si hay suficiente. Así no existe hueco entre leer y escribir.
Transacciones con el nivel de aislamiento adecuado. Agrupan operaciones para que se apliquen todas o ninguna, y el nivel de aislamiento decide qué ven las demás mientras tanto.
Bloqueo pesimista. Bloquear la fila mientras trabajas. Es seguro y penaliza: los demás esperan, y hay riesgo de bloqueo mutuo si dos procesos se bloquean el uno al otro.
Bloqueo optimista. Cada fila lleva un número de versión. Al guardar, se comprueba que la versión sigue siendo la que leíste; si cambió, alguien te adelantó y hay que reintentar. Es la mejor opción cuando los conflictos son raros, y es lo que da el mensaje «este registro ha sido modificado por otro usuario».
Restricciones de unicidad. Un índice único es la última línea de defensa y no falla: aunque la lógica tenga un hueco, la base de datos rechaza el duplicado.
Ejemplo práctico
En un sistema de gestión hay tres sitios donde la concurrencia muerde de verdad:
Numeración de documentos. Calcular el siguiente número leyendo el máximo y sumando uno produce duplicados el día que dos personas facturan a la vez. Debe generarlo la base de datos, con índice único encima.
Stock. El caso de arriba, tal cual.
Edición simultánea de la misma ficha. Dos comerciales abren el mismo cliente, uno cambia el teléfono y el otro la dirección, y el segundo en guardar pisa el cambio del primero sin que nadie se entere.
Lo que aprendí: ese último es el más frecuente y el que menos se protege, porque no rompe nada visible — simplemente se pierde información en silencio. El bloqueo optimista lo resuelve con un campo de versión y un aviso al usuario.
El segundo aprendizaje, y es incómodo: estos fallos no se detectan probando. Un solo usuario nunca los provoca. Se detectan razonando sobre el código, con una pregunta muy concreta en cada punto donde se lee y luego se escribe: ¿qué pasa si otro proceso hace esto mismo justo entre las dos líneas? Si la respuesta es «un desastre», hay que protegerlo — aunque nunca haya pasado.
Y una advertencia sobre las tareas periódicas: si un proceso tarda más de su intervalo, puede arrancar una segunda copia mientras la primera sigue trabajando, y ambas procesan lo mismo. Hace falta un cerrojo que impida el solapamiento. Ver tarea programada.
Errores comunes
- Leer, calcular y escribir sin protección.
- Generar números correlativos en el código.
- No detectar la edición simultánea, y perder cambios en silencio.
- Confiar solo en la lógica sin restricciones de unicidad en la base de datos.
- Tareas periódicas que se solapan.
- Bloquear demasiado, hasta convertir el sistema en una cola.
- Descartarlo por improbable. Con volumen suficiente, lo improbable ocurre a diario.
Cuándo revisarlo
Siempre que haya varios usuarios sobre los mismos datos, en toda numeración de documentos, en control de stock y en cualquier proceso periódico.
La pregunta que lo destapa: ¿qué pasa si esto se ejecuta dos veces exactamente a la vez? Si la respuesta no es tranquilizadora, ya tienes el próximo arreglo. Ver también idempotencia.