example - new icon java
Transacción de primavera REQUERIDA vs REQUIRES_NEW: transacción de reversión (2)
Tengo un método que tiene la propagation = Propagation.REQUIRES_NEW
propiedad transaccional:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createUser(final UserBean userBean) {
//Some logic here that requires modification in DB
}
Este método se puede llamar varias veces al mismo tiempo, y para cada transacción si ocurre un error que se revierte (independientemente de las otras transacciones).
El problema es que esto podría obligar a Spring a crear varias transacciones, incluso si hay otra disponible, y puede causar algunos problemas de rendimiento.
Java doc of propagation = Propagation.REQUIRED
dice: Support a current transaction, create a new one if none exists.
Esto parece resolver el problema de rendimiento, ¿no?
¿Qué pasa con el problema de reversión? ¿Qué pasa si una nueva llamada al método se retrotrae mientras se usa una transacción existente? ¿No revertirá toda la transacción incluso las llamadas anteriores?
[EDITAR] Creo que mi pregunta no era lo suficientemente clara:
Tenemos cientos de clientes conectados a nuestro servidor.
Para cada cliente, naturalmente, necesitamos enviar un comentario sobre la transacción (OK o excepción -> reversión).
Mi pregunta es: si utilizo REQUIRED
, ¿significa que solo se usa una transacción y si el cliente número 100 encuentra un problema, la transacción del primer cliente también se revertirá?
El uso de REQUIRES_NEW
solo es relevante cuando se invoca el método desde un contexto transaccional; cuando se invoca el método desde un contexto no transaccional, se comportará exactamente como REQUIRED
: creará una nueva transacción.
Eso no significa que solo habrá una sola transacción para todos sus clientes: cada cliente comenzará desde un contexto no transaccional, y tan pronto como el procesamiento de la solicitud llegue a un @Transactional
, creará una nueva transacción.
Entonces, teniendo esto en cuenta, si usar REQUIRES_NEW
tiene sentido para la semántica de esa operación -de lo que no me preocuparía el rendimiento- esto sería una optimización prematura del libro de texto. Prefiero enfatizar la corrección y la integridad de los datos y preocuparme por el rendimiento una vez que sido recogido, y no antes.
Al retroceder, el uso de REQUIRES_NEW
forzará el inicio de una nueva transacción, por lo que una excepción revertirá esa transacción. Si también hay otra transacción que se estaba ejecutando, que se retrotraerá o no se revertirá dependiendo de si la excepción sube la pila o se detecta, tu elección depende de los detalles de las operaciones. Además, para una discusión más profunda sobre las estrategias transaccionales y la reversión, recomendaría: «Estrategias de transacción: comprender las trampas de las transacciones», Mark Richards .
Si realmente necesita hacerlo en una transacción por separado, necesita usar REQUIRES_NEW
y vivir con la sobrecarga del rendimiento. Cuidado con los bloqueos muertos.
Prefiero hacerlo de otra manera:
- Validar datos en el lado de Java.
- Ejecuta todo en una transacción.
- Si algo sale mal en el lado de la base de datos -> es un error importante de DB o diseño de validación. Revertir todo y lanzar un error crítico de nivel superior.
- Escribe buenas pruebas unitarias.