2011-04-16 17 views
8

Medio Ambiente: Primavera 3, gestión de transacciones con clientes, transacciones JDBCCómo llamar a un método de reversión personalizado en Spring Transaction Management?

que acabo de leer la documentación de la primavera en el uso de la plantilla de transacción para manejar la gestión de transacciones. Parecía demasiado complejo por lo que quiero preguntar:

La mayoría de mis transacciones son JDBC relacionado, lo que significa que acaba de declarar una @Transactional en mi servicio. Pero ahora, Estoy realizando una llamada de servicio REST a otro sitio que necesita deshacerse si cualquiera de las siguientes operaciones JDBC falla, en este caso proporcionaré el código de restitución.

a medida que avance en mi método, en mi transacción - Quiero guardar una referencia a la llamada de servicio REST (necesario para hacer retroceder esa acción), y sobre la excepción acabo quieren un método myCustomRollback() llama cuales puede acceder al objeto previamente almacenado.

¿Por qué no simplemente proporciona un mapa en la transactionTemplate para almacenar cosas y definir un método de reversión personalizado en la anotación @Transactional?

Así es como lo pienso, no estoy siguiendo la forma en que Spring piensa sobre esto. ¿Alguien puede ayudarme a cerrar la brecha entre lo que quiero y cómo lo logro de manera más eficiente en la primavera? Solo necesito hacer esto para algunas operaciones de casos especiales.

Respuesta

0

puede utilizar el consejo AfterThrowing (cuando se produce una excepción) & llame a su método (myCustmRollback()) allí, se puede utilizar TransactionSynchronizationManager clase para obtener thecurrent transacción & rollo de nuevo ...

, alternativamente, se .. puede utilizar el AroundAdvice para comenzar & commit/rollback su transacción (de esta manera se puede utilizar el administrador de transacciones de resorte proporcionada por el uso de la clase TransactionSynchronizationManager)

1

primavera gestión de transacciones el comportamiento predeterminado de reversión automática es para excepciones sin marcar

así que para una excepción personalizada,

@Transactional(rollbackFor = CustomException.class, noRollbackFor = RuntimeException.class) 
public void doSomething(... 
) 

la transacción pueden deshacer si hay una excepción que coincide con el especificado. Si una excepción no partidos, se propaga a llamante del servicio o TransactionRolledBackException envoltorio

si utiliza utilizar el org.springframework.transaction.PlatformTransactionManager es manejo de excepciones más manejable que la plantilla

verificación de la documentación http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html

4

He vuelto a leer su pregunta varias veces y no estoy seguro de entender su pregunta por completo. Supongo que está ejecutando algúnCódigo y si eso no funciona, desea ejecutar myCustomRollback que tiene alguna información sobre someCode. Por lo tanto, intentaré proporcionar una respuesta genérica.

Si desea que el resorte revierte algún código. Solo revertirá lo que es rollBackAble, como las transacciones jdbc. Supongamos que tiene un método que realiza 2 llamadas.

@Transactional 
public void doStuff(SomeEntity entity, File file) { 
    persist(entity); 
    customFileService.createOnFileSystem(file); 
    throw new RunTimeException(); 
} 

Así que el código anterior siempre se revertirá. Deshace la persistencia de su entidad, pero no la creación de su archivo, ya que las transacciones de Spring no lo gestionan, a menos que proporcione una implementación personalizada.

En segundo lugar, un resorte que proporciona 2 formas de trabajar con transacciones:

  • primavera AOP: un proxy se crea en tiempo de ejecución la que va a decorar su código con la materia transaccional. Si su clase se llamaría MyClass, Spring creará los nombres de clase MyClassProxy, que envolverá su código en código transaccional.
  • AspectJ: en el momento de la compilación, su archivo .class se ajustará y el código transaccional se integrará en su método.

El enfoque aspectJ parece más difícil de configurar, pero no tanto y es mucho más fácil de usar. Dado que todo lo que se anota con @Transactional se incrustará (tejida) con el código. Para Spring AOP este no es el caso. ¡Las llamadas al método interno transaccional por ejemplo en Spring serán ignoradas! AspectoJ proporciona un enfoque más intuitivo.

Volver a lo que creo que su pregunta es (el código es todo en 1 clase):

public void doSomeCode() { 
    Object restCall = initialize(); 
    try { 
     execute(restCall); 
    } catch (CustomException e) { 
     myCustomRollback(restCall; e); 
    } 
} 

@Transactional(rollbackFor = CustomException.class) 
private void execute(Object restCall) throws CustomException { 
    // jdbc calls.. 
     restCall = callRest(restCall); 
     throw new CustomException(); 
} 

void myCustomRollback(Object restCall, CustomException e) { 
    ... 
} 

El código anterior sólo funcionará con AspectJ! ¡Desde su método interno llama que también parece ser privado! AOP en tiempo de ejecución no puede manejar esto.

Entonces, ¿qué pasa es que todo (que es rollbackAble) en la ejecución se revertirá. Y en doStuff tiene información sobre los objetos que se utilizaron en la ejecución, ahora puede usar en myCustomRollback para deshacer su material REST de forma manual.

No estoy seguro de haber respondido correctamente esta pregunta, pero espero que ayude a alguien con un problema similar.

0

1 solución es implementar su propio gestor de transacciones mediante la extensión de una solución de un

2 es utilizar la clase TransactionSynchronizationManager

3 solución es utilizar @TransactionalEventListener en caso de tener Spring 4

2

Para Alguien sigue leyendo esto:

Resolví un problema similar con los eventos de primavera - según lo sugerido por Den Roman en la opción 3. Aquí está el básico idea (escenario es ficticio):

Siempre que puedo realizar operaciones externas que deben ser laminados juntos de nuevo con la transacción, publico un evento dentro de mi @Transactional método que utiliza el apoyo de muelle (org.springframework.context.ApplicationEventPublisher):

@Transactional 
public String placeOrder(Order order) { 
    String orderId = orderServiceGateway.createOrder(order); 
    applicationEventPublisher.publishEvent(new OrderCreatedEvent(orderId)); 
    workflowService.startWorkflow(orderId); 
    return orderId; 
} 

El evento en sí puede ser cualquier objeto. Creé un POJO con detalles sobre la entidad remota que se eliminará.

Entonces registró un detector de eventos especiales que se une a una fase de transacción - en mi caso a la reversión:

@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK) 
public void rollBackOrder(OrderCreatedEvent orderCreatedEvent) { 
    String orderId = orderCreatedEvent.getOrderId(); 
    orderServiceGateway.deleteOrder(orderId); 
} 

Por supuesto, se recomienda coger & ingrese la excepción de operación de reversión, no pierda la excepción original del método placeOrder().

De forma predeterminada, estos eventos son síncronos, pero se pueden realizar de forma asíncrona mediante una configuración adicional.

Aquí hay un muy buen artículo sobre este mecanismo, incluyendo la configuración detallada y escollos: Transaction Synchronization and Spring Application Events (DZone)

Si bien no me gusta la solución 100%, ya que estorba la lógica de negocio con la publicación de sucesos cosas y se une a la primavera, se definitivamente hace lo que espero que haga y permite pasar el contexto del método transaccional al método de reversión, que no está disponible a través de un bloque try/catch tradicional fuera del método transaccional (a menos que coloque su contexto en la excepción misma) , que no es muy agradable).

Cuestiones relacionadas