How to call native rollback method in Spring Transaction Management?

Environment: Spring 3, custom transaction management, JDBC transactions

I just read the Spring docs about using a transaction template to manage transactions. It seemed too complicated, so I want to ask:

Most of my transactions are JDBC related, i.e. I just declare @Transactional in my service. But now I am making a REST service call to another site, which should roll back if any of the following JDBC operations fail , in which case I provided a rollback code.

As I move along my method, in my transaction I want to keep the link to the REST service call (you need to cancel this action), and after the exception, I just want the myCustomRollback() method, called , which can access the previously saved object .

Why not just provide a map in the transactionTemplate file for storing material and define a rollback method in the @Transactional annotation?

So I think about it, I do not follow how Spring thinks about it. Can someone help me bridge the gap between what I want and how I most efficiently execute it in Spring? I need to do this for only a few case-specific operations.

+8
java spring spring-mvc transactions
source share
5 answers

you can use AfterTrowing advice (when an exception is thrown) and call your method ( myCustmRollback() ) there, you can use the TransactionSynchronizationManager class to get the current transaction and return it back ...

alternatively .. you can use AroundAdvice to start and commit / roll back your transaction (this way you can use the provided spring transaction manager using the TransactionSynchronizationManager class)

0
source share

I re-read your question several times and am not sure that I fully understand your question. I assume you are executing someCode , and if that fails, you would like to execute myCustomRollback , which has some information about someCode. Therefore, I will try to provide a general answer.

If you want spring to undo some code. It will only rollback, which is rollBackAble, like a jdbc transaction. Suppose you have a method that makes 2 calls.

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

Thus, the code above will always be rolled back. It will undo the preservation of your entity, but not the creation of your file, as this is not controlled by spring transactions unless you provide them with a specific implementation.

Secondly, spring provides two ways to work with transactions:

  • Spring AOP: A proxy is created at runtime that decorates your code with transactional material. If your class is called MyClass, spring will create the class names MyClassProxy, which will contain your code in the transaction code.
  • AspectJ: at compile time, your .class file will be adjusted, and the transaction code will be embedded in your method.

The aspect approach seems more difficult to configure, but it is not so much and easier to use. Since everything annotated with @Transactional will be nested (woven) with code. For spring, AOP is not the case. An internal transaction call, such as in spring, will be ignored! As such, aspectJ provides a more intuitive approach.

Return to what I think your question is (the code is only in 1 class):

 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) { ... } 

The above code will only work with AspectJ! . Because you are calling internal method calls that also seem private! AOP at runtime cannot handle this.

So what happens, everything (that rollbackAble) in execution will be undone. And in doStuff you have information about the objects that were used during execution, now you can use in myCustomRollback to manually roll back your REST elements.

Not sure if I answered this question correctly, but I hope this helps someone with a similar problem.

+4
source share

Who are still reading this:

I solved a similar problem with spring events - as suggested by Den Roman in option 3. Here's the main idea (a fictitious script):

Whenever I perform external operations that need to be canceled along with the transaction, I post an event inside my @Transactional method, using support from spring ( 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; } 

The event itself can be any object - I created a POJO with details about the deleted entity that needs to be deleted.

Then I registered a special event listener attached to the transaction phase - in my case, to rollback:

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

Of course, it is recommended to catch and register an exception from the rollback operation so as not to lose the original exception from the placeOrder() method.

By default, these events are synchronous, but they can be done async using an additional configuration.

Here's a very good article on this mechanism, including detailed configuration and traps: Transaction Synchronization and spring Application Events (DZone)

While I donโ€™t like the solution 100% because it clutters the business logic with event publishing and communicates with spring, it definitely does what I expect from it and allows the context to be passed from the transactional method to the rollback method - which not available through the traditional try / catch block outside the transaction method (unless you put your context in the exception itself, which is not very nice).

+3
source share

Spring transaction management default behavior for automatic rollback for thrown exceptions

therefore for custom exception

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

The transaction will be discarded if there is an exception matching the specified. If the exception does not match, it is thrown to the caller of the service or to the TransactionRolledBackException wrapper

if you use using org.springframework.transaction.PlatformTransactionManager, this is more controlled exception handling than pattern

check documentation http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html

+1
source share

Solution 1 is to implement your own transaction manager by expanding one

2 solution is to use the TransactionSynchronizationManager class

Decision

3 is to use @TransactionalEventListener in case you have Spring 4

0
source share

All Articles