java - manager - timeout transaction spring
¿Cómo reiniciar transacciones en deadlock/lock-timeout en Spring? (4)
¿Cuál es la mejor práctica para implementar un reinicio de transacción en caso de interbloqueo o excepciones de bloqueo de tiempo de espera cuando se utiliza Spring (específicamente el enfoque recomendado por Spring: transacciones declarativas)?
Gracias,
Asaf
No hay una respuesta universal porque depende de los detalles de la aplicación. Por ejemplo, es posible que desee realizar un reinicio automático de la operación transaccionada o notificar al usuario sobre un error de operación y solicitar una confirmación de reintento explícita, etc.
Usaría AOP en caso de un escenario de reinicio automático.
Siento que Spring debería tener una buena respuesta a esta pregunta (en forma de documentación, como mínimo, o un interceptor de reintentos de algún tipo). Por desgracia, no es así.
Probablemente, la mejor manera de manejar los reintentos (si desea continuar siendo "declarativo" sobre las cosas) es escribir su propia implementación de interceptor que automáticamente reintentará la transacción una cantidad de veces configurada. Para empezar, estudia el TransactionInterceptor
de Spring, que maneja el comportamiento de inicio / retroceso / confirmación para las transacciones declarativas. Si está utilizando Hibernate, observe cómo maneja la vinculación / desvinculación de sesión de Hibernate con el Thread actual.
Cosas a tener en cuenta si estás usando Hibernate:
- Su "interceptor de reintentos" debe asegurarse de desvincular cualquier sesión Hibernate preexistente enlazada a hilos y volver a enlazar una nueva. Una vez que se lanza una excepción (por ejemplo, interbloqueo) desde el código de Hibernate / JDBC, la sesión de Hibernate correspondiente se envenena y debe descartarse. (
session.clear()
no es suficiente.) - Tenga cuidado si sus métodos de servicio transaccional usan objetos de sesión de Hibernate como parámetros de método. Cuando vuelva a intentarlo, cuando reinicie su sesión de Hibernate, estos objetos se separarán. Tendrá que volver a conectarlos si el método de servicio supone que están adjuntos (por ejemplo, si usan propiedades cargadas perezosas a las que se acceda en el método de servicio, o si intenta guardarlas, etc.) En general, es mejor si no use objetos de Hibernate como parámetros para los métodos de servicio transaccional.
- Implementarás
MethodInterceptor.invoke()
: la instancia deMethodInvocation
que se transfiere a esto puede ser con estado; Es posible que deba clonarlo antes de usarlo en el interceptor.
Recomiendo usar la clase org.springframework.retry.interceptor.RetryOperationsInterceptor
del proyecto de reintentos de primavera, configurado de esta manera :
<aop:config>
<aop:pointcut id="transactional" expression="execution(* com...*Service.remoteCall(..))" />
<aop:advisor pointcut-ref="transactional" advice-ref="retryAdvice" order="-1"/>
</aop:config>
<bean id="retryAdvice" class="org.springframework.retry.interceptor.RetryOperationsInterceptor"/>
Pero si aún desea implementarlo usted mismo, el ejemplo de AOP de la documentación de primavera es un buen comienzo.
Tuve la misma pregunta hace varios años y terminé escribiendo mi propia solución como aspecto de AOP, que termina pareciéndose a esto en su código:
@RetryTransaction
@Transactional
public void doSomething() {
....
}