Spring4 Junit4 Test: #TransactionConfiguration VS #Transactional, use only one or together? - spring

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".

Related

Why do we need to annotate the Service class with #Transactional in Spring Data JPA

In a spring boot app, we have user-defined repository interface that extends JpaRepository.
JpaRepository in turn is has an implementation class SimpleJpaRepository.
SimpleJPARepository has 2 annotations on it
#Transactional
#Repository
So we can skip these 2 annotations on our user-defined repository interface that extends JpaRepository.
Then why do we need to explicitly add #Transactional over service class which is also using our user-defined repository object only?
The point of having the Transactional annotation is so that everything in the annotated method occurs within the same unit of work and either everything succeeds or everything fails. Putting Transactional only on each repository means each repository can have its own transaction, and the second one failing doesn't rollback the first one.
You can have nontransactional methods on a service, or every method so annotating a class as a Service doesn't mean spring can assume everything is transactional.
This is a has vs is problem.
An object can be Transactional, or have a member object that is Transactional.
If the object has a member object that is Transactional, it is not automatically Transactional itself.
Object A contains Object B which is Transactional, that does not make Object A Transactional.

What is the replacement of EJB SessionContext object in spring boot?

I am migrating an EJB project to Spring boot project. I have successfully replaced other annotations to the spring annotation, but havving problem with SessionContext object.
My legacy code is bellow
#Resource
SessionContext sessionContext;
.....
if (some condition) {
sessionContext.setRollbackOnly();
return false;
}
For this code i am getting the following error
A component required a bean of type 'javax.ejb.SessionContext' that could not be found.
Action:
Consider defining a bean of type 'javax.ejb.SessionContext' in your configuration.
I think you'll have to use a few different functionalities.
setRollbackOnly()
Most often I have seen Session Context used for Rollbacks. In Spring, you can replace this with:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
or annotate class with
#Transactional(rollbackFor = MyException.class)
so you can throw your exception from class to cause rollback.
getBusinessObject()
The second most commonly used feature is method to load a business object so that I can, for example, create a new transaction within a same bean. In this case you can use Self-inject:
#Lazy private final AccountService self;
and annote method with #Transactional. This, of course, solves any other cases where you need to use the power of a proxy object.
Other functionality is provided by other classes in Spring, but I think that these two are the most commonly used in the Java EE world and when migrating, one will look to replace them in Spring.

How can I replicate the rollback from Entity Manager with JPA Repository?

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.

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.

omit transactions for specific methods in spring

I'm using the #Transactional annotation for my entire Dao class with spring and hibernate. Everything works great, it's just that I would like to omit the behaviour for a few non database related methods in my Dao.
http://static.springsource.org/spring/docs/2.5.4/reference/transaction.html#transaction-declarative-annotations
Every time I step into these methods during a debugging session, I always get to JdkDynamicAopProxy.class which is super annoying.
Is there any way to omit transactional for specific methods? Or at least fix this annoying debugging behavior?
In Spring you can put the #Transactional annotation on only the methods you want to make transactional, instead of putting it at the class level.
Otherwise perhaps consider extracting those specific non-transactional methods into a separate class?

Resources