Considere la aplicación web java Spring MVC , que proporciona alguna REST API .
Digamos que tiene muchos métodos, uno de ellos es DELETE /api/foo/{id} , que obviamente elimina la entidad foo de la base de datos con la id dada.
El problema es que debido a los grandes datos en la base de datos, esta operación no es inmediata, por lo que si el cliente intenta realizar simultáneamente operaciones de eliminación de multiplicación en la misma entidad, digamos
DELETE /api/foo/123 x N veces (por error en el software del cliente, por supuesto),
provoca algunos efectos secundarios desagradables en la base de datos (ya sabe, si intenta eliminar la misma entidad en varias transacciones, eso generalmente no es bueno).
Mi pregunta es: ¿cuál es la mejor práctica en Spring MVC para prevenir tales situaciones?
Ciertamente puedo introducir la sincronización en Foo id en cada método de actualización ( PUT/DELETE ). Sin embargo, tendré que hacerlo para todas las entidades y todos los métodos de API PUT/DELETE , lo cual realmente no quiero hacer. Supongo que debería ser una solución elegante y agradable, cómo realizar este tipo de sincronización en el nivel de interceptor/servlet, es decir, no en el nivel de servicio del controlador.
También puedo crear un interceptor específico y actuar allí esperando solicitudes duplicadas (solicitudes con la misma URL y parámetros). Pero, de nuevo, no suena como una solución elegante (hasta que me asegure de que no es posible configurar en Spring MVC de alguna manera de una manera más hermosa).
Ese es un problema de concurrencia que debe manejarse utilizando la transacción adecuada y el nivel de bloqueo. Desafortunadamente, no hay un tamaño único que se ajuste a todos aquí y, según sus requisitos reales, es posible que deba implementar un bloqueo optimista o pesimista, así como uno de los posibles niveles de transacción (desde ninguna transacción hasta transacciones serializables).
En general, manejar tales preguntas a nivel web es una mala idea, porque terminará con preguntas como ¿qué hacer si se solicita eliminar algunos datos que otro está mostrando al mismo tiempo? En SpringMVC, la forma común es usar métodos transaccionales en la capa de servicio. Además, debe declarar un sistema de bloqueo optimista o pesimista en la capa de persistencia.
La capa optimista normalmente brinda un mayor rendimiento, a costa de que algunas transacciones terminen en excepciones. En ese caso, las mejores prácticas actuales ahora son informar el problema al usuario pidiéndole que envíe su solicitud nuevamente.