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.
Related
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.
I am converting a project from Spring framework to Spring boot, so I am no longer using persistence files and other config files.
Also, I gave up using Entity Manager, instead I created repositories which extend JPA Repository, so that I can use the functions from there. The only thing is that I have some unit tests and in the Spring framework, at the end of each test there is a finally clause which has a rollback, so that the data from the database to be specific to each test.
How can I do that without Entity Manager? I tried using the flush() method, but no result...
By default, data JPA tests are transactional and roll back at the end of each test.
You can refer to Enabling and Disabling Transactions in spring test documentation which indicate :
Annotating a test method with #Transactional causes the test to be run within a transaction that is, by default, automatically rolled back after completion of the test. If a test class is annotated with #Transactional, each test method within that class hierarchy runs within a transaction. Test methods that are not annotated with #Transactional (at the class or method level) are not run within a transaction. Furthermore, tests that are annotated with #Transactional but have the propagation type set to NOT_SUPPORTED are not run within a transaction.
Tips :
If you want to commit the transaction for a reason or another, you can use the #Commit annotation or less properly #Rollback(false) on method or class level.
If you want to execute code outside of a transaction ( before or after ) you can use #BeforeTransaction and #AfterTransaction on public methods that have no return ( return void ) or on default method of interfaces.
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?
In My junit test case:
I use only #transactional at class or one, each test method will roll back, because each method within running a transaction. And I add it at method, then the assigned method will roll back.
I use only #TransactionConfiguration(defaultRollback = true) at class, but the transaction is not work.
I use #transaction and #TransactionConfiguration(defaultRollback = true) at class together, also it will be roll back.
My issue:
Why roll back is not work with only #TransactionConfiguration at class?
I see #transactional default bean name is transaction manager and roll back is TRUE, so i only add it at class and not #TransactionConfiguration?
#transactional must annotation, is #TransactionConfiguration only assign transaction manager in multi-transactionManager case?
#transactional causes each method to be run within a transaction, and you can configuration, isolation etc by #transactional.
You can configuration transaction manager with #TransactionManager in multi-TransactionManager. So transaction is not work if you only use this annotation.
Because each method to be run within a transaction, then you can change it with #RollBack(false).
In https://docs.spring.io/spring/docs/4.3.x/javadoc-api/org/springframework/test/context/transaction/TransactionConfiguration.html, They say #TransactionConfiguration is "Deprecated" and "As of Spring Framework 4.2, use #Rollback or #Commit at the class level and the transactionManager qualifier in #Transactional".
I am working on an application which involves mule, spring, hibernate with annotations. I am using org.springframework.orm.hibernate3.HibernateTransactionManager. Now the problem is :
I have certain components in mule which logs data into db based on conditions using hibernate. I have used #Transactional which inserts few data and then commits the transaction when the method scope is completed. But the behaviour which i want is : first component inserts data based on some condition, but the transaction should not commit immediately, again my second component that is a java class should insert some data again then third etc. if any of the component fails all the queries executed in all the components should be rolled back. all of this components are separate java classes
How can i achieve such behaviour.
thank you,
Let your whole component execution chain be in a transaction. then it will meet your expectation. it is easy to do it if all your components are in the same one spring appliction context. In the case, there are two things you need to do:
Add #Transactional annotation on your component class or specific methods which need to be in transaction. By default, transactional method use REQUIRED Propagation setting which will let all method in the exection chain merge to only one transaction.
Make sure Spring can scan all your components.
#Transactional
#Component( "lbsProviderApiCallJob" )
public class LbsProviderApiCallJoImpl implements LbsProviderApiCallJob, ApplicationContextAware {
If all your component are not in a spring context. it is complex to make it.