Rolling back a transaction in Spring ApplicationListener - spring

Normal Spring ApplicationListners are running synchronously within the same thread of the event publisher.
Is there any way to rollback the main context transaction in the listener?
I have a method annotated #Transactional and it publishes an event, I want to make execute the listeners in the scope of the main method, and rollback the main transaction in case of exceptions.
I am using a LocalTransactionManager on Hibernate SessionFactory.
Is there any way to do this using Spring 3.3.x?

Related

Spring: Side effects of #Async on Transactions handling?

I have a Spring Boot REST API through which a web client can start the execution of a testsuite. The handling of the transactions was tricky, but i finally made it and everything work as expected. This is my setting:
the http request is handled by a controller (1)
when receiving the request, the controller publishes an event "start testsuite" (I use the Spring Event handling)
a method with #EventListener (2) listens to that event and calls the method in charge of the testsuite execution (3).
Now it turns out that the execution of the testsuite is sometime very long. As I don't want the http request to remain pending too long, I'd like to make the testsuite execution asynchron. To achieve that I added a #Async at the method of the service layer in charge of the testsuite execution(3).
As a result: I can tell that the process runs now indeed async but the testsuite execution behave in a weird way that make me think the transactions are not handled correctly anymore. So what I'm trying to understand, and that's the object of this question: in which way the #Async can, in this configuration, have side effects on the transaction handling?
I did some research. According to this article
If the #Async annotation is being used extra care should be taken with respect to transactions. In normal circumstances (without #Async) a transaction gets propagated through the call hierarchy from one Spring #Component to the other. However, when a #Transactional Spring #Component calls a method annotated with #Async this does not happen. The call to the asynchronous method is being scheduled and executed at a later time by a task executor and is thus handled as a 'fresh' call, i.e. without a transactional context. If the #Async method (or the #Component in which it is declared) is not #Transactional by itself Spring will not manage any needed transactions.
I get that point, but I don't think I'm in this situation since the calling method of the async method (= the event listener) has not been made transactional.
Does anyone have a clue?

Understanding Spring AOP and Transaction Aspect

I was studying about the Proxy Object which spring gives when we autowire any interface. This is a very good link for understanding that https://www.youtube.com/watch?v=bEvGdWjeCy4&t=310s. Here he explains that If a POJO implements any interface then Spring proxy bean also implements that interface (using JDK Proxy mechanism) and adds additional logic such as transactional logic (if the method was annotated using jdbc code or delegating it to PlatformTransactionManager). Spring gives us a wrapper object which has the reference to the real object and it has additional code which it runs before and after the original method is invoked using MethodInvocationHandler. So My question is that how exactly spring is managing that transaction.Where that jdbc code to get connection and start transaction is written. Is it in the Spring Proxy object or any Aspect Class.
As in AOP there as Aspects which are basically the cross cutting concerns such as transaction common to the whole application. Is Spring inserting Transaction behavior code in the Proxy Object or is it Using PlatformTransactionManager to do that And Where does This AOP fits in this Flow. How the Aspect handling Transactional behavior getting invoked here if it is. How the call is getting transferred to it?
In term of JDK proxy , you have to supply a InvocationHandler implementation when creating a proxy object. When the proxy object is invoked , this InvocationHandler will be invoked around the actual object. (see this for a hello world example for how does JDK proxy works)
In term of the spring transaction , it already shipped with an InvocationHandler implementation (i.e. JdkDynamicAopProxy). It will then somehow invoke the transaction aspect (i.e. TransactionInterceptor). The transaction aspect is responsible for controlling the whole workflow such as when to create , commit or rollback the transaction and when to actually execute the actual method etc.
The transaction aspect also delegates to the PlatformTransactionManager to actually start , commit and rollback a transaction. Because different technologies has their own ways to start , commit and rollback a transaction , it is necessary to introduce a PlatformTransactionManager as an interface to abstract these operations such that we can switch different transaction technology by simply switching the PlatformTransactionManager implementation inside the transaction aspect .
So back to your questions :
Where that jdbc code to get connection and start transaction is
written. Is it in the Spring Proxy object or any Aspect Class.
None of them. It is actually the PlatformTransactionManager to get the connection and start the transaction which is invoked by the aspect.
Is Spring inserting Transaction behaviour code in the Proxy Object or
is it Using PlatformTransactionManager to do that And Where does This
AOP fits in this Flow.
Spring inserts the transaction behaviour in the aspect object (i.e. TransactionInterceptor). The aspects then delegate to the PlatformTransactionManager to actually start , commit and rollback the transaction.
How the Aspect handling Transactional behaviour getting invoked here
if it is. How the call is getting transferred to it?
Assuming the JDK proxy is used , the call flow is something like :
Someone invokes on the JDK proxy
InvocationHandler of this proxy will be invoked (i.e JdkDynamicAopProxy)
InvocationHandler somehow calls spring transaction aspect (i.e TransactionInterceptor)
Transaction aspect delegates to PlatformTransactionManager to actually start , commit and rollback the transaction if necessary.

How to rollback unit test while service layer is #Transactional

I am using Spring Boot 1.5.2.RELEASE and my service classes is annotated with
#Service
#Transactional(rollbackFor = Exception.class)
My unit test class is annotated with:
#RunWith(SpringRunner.class)
#SpringBootTest
I wish to roll back changes made in the database by unit test methods after test is finished.
One of the proposed solutions is to add #Transactional annotation over the test class, I tried it but this solution produces some issues, is that sometimes the test transaction is rolled back (even without no exceptions thrown!) before the service transaction is completed.
Is there another good solution to rollback test?
The solution with the #Transactional on the test class is the standard way of doing this. There is no way Spring Tx would roll back a transaction out of the blue, so I'd recommend looking closer into the issues that you encountered instead of inventing other solutions.
all changes will be rollbacked if didn't change default behaviour. And you don't have classes / methods with transaction propagation level = REQUIRES_NEW as it start independent transaction and can commit or rollback independently with the outer transaction
Transaction rollback and commit behavior
By default, test transactions will be automatically rolled back after
completion of the test; however, transactional commit and rollback
behavior can be configured declaratively via the #Commit and #Rollback
annotations.
#Rollback
#Rollback indicates whether the transaction for a transactional test
method should be rolled back after the test method has completed. If
true, the transaction is rolled back; otherwise, the transaction is
committed (see also #Commit). Rollback semantics for integration tests
in the Spring TestContext Framework default to true even if #Rollback
is not explicitly declared.
When declared as a class-level annotation, #Rollback defines the
default rollback semantics for all test methods within the test class
hierarchy. When declared as a method-level annotation, #Rollback
defines rollback semantics for the specific test method, potentially
overriding class-level #Rollback or #Commit semantics.
From the docs:
By default, test transactions will be automatically rolled back after
completion of the test; however, transactional commit and rollback behavior can be configured declaratively via the #Commit and #Rollback annotations.
Your comment:
sometimes the test transaction is rolled back (even without no
exceptions thrown !) before the service transaction is completed !
doesn't make sense to me. How did you know whether the txn completed or not if it was rolled back? Exceptions don't matter for tests, as I quoted the doc above.

struts2 and spring transactions

I have a app written with struts2 and spring and JPA over hibernate. Form spring i use transactions and IoC.
My app is structured in 2 layers : Struts Actions and some "services" classes that are dealing with CRUD operations, classes that are annotated with #Transactional.
If in one of these services classes method an exception occurs i have to throw that exception from this class(to struts action level) in order for Spring to rollback transaction automatically, right?
What will happen otherwise (if a don`t throw that exception and the transaction will never rollback) ?
PS. i use spring managed EntityManager for all DB operations.
Thanks

SessionContext RollBackOnly and MDB's

Having an MDB that receives a message in a transaction and then does several EJB calls if I call in one of those EJB's this.sessionContext.setRollbackOnly() will this trigger the JMS message's redelivery ?
All the EJB methods are marked with Requires_New transaction attribute.
No, because the MDB's transaction will be suspended while EJBs annotated with #REQUIRES_NEW are being processed — each within its own transaction. Additional assumption is that setRollbackOnly() is the only effect of rolling back an EJB's transaction, that is the EJB exited properly and did not throw any exception (after voting for rollback, further interaction with the resource may cause an exception from the javax.ejb.EJBException family to be thrown).

Resources