Reputation: 63
I have @Transactional
method in controller class as below :
Main issue is each service call runs in its own transaction as per the log.
Is the transactional functionality ignored for controllers?
I expect the student record not get saved as I am throwing exception after that using another service, but still the update happens in the database. I even have @EnableTransactionManagement
on the config class. can you please help me with this.
@RestController
@RequestMapping("/api")
public class Resource {
@Transactional
@RequestMapping(value="/test", method = RequestMethod.PUT, produces = "application/json")
public StudentDTO updateRecord(@RequestBody StudentDTO DTO) throws ApplicationException{
studentservice.find(1234); //jparepository.findone() runs in one transaction
studentservice.save(dto); //jparepository.save() runs in one transaction
testservice.throwException(); // this method throws application exception
}
@Configuration
@ComponentScan(basePackages={"com.student.*"})
@EnableAutoConfiguration(exclude = {MetricFilterAutoConfiguration.class, MetricRepositoryAutoConfiguration.class})
@EnableConfigurationProperties
@EnableTransactionManagement
public class Application {
}
below is the log :
[TRACE] org.springframework.transaction.interceptor.TransactionInterceptor - Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findOne]
[TRACE] org.springframework.transaction.interceptor.TransactionInterceptor - Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findOne]
[TRACE] org.springframework.transaction.interceptor.TransactionInterceptor - Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
[TRACE] org.springframework.transaction.interceptor.TransactionInterceptor - Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
[TRACE] org.springframework.transaction.interceptor.TransactionInterceptor - Completing transaction for [updaterecord] after exception: xx.xx.ApplicationException
[TRACE] org.springframework.transaction.interceptor.RuleBasedTransactionAttribute - Applying rules to determine whether transaction should rollback on xx.xx.ApplicationException
[TRACE] org.springframework.transaction.interceptor.RuleBasedTransactionAttribute - Winning rollback rule is: null
[TRACE] org.springframework.transaction.interceptor.RuleBasedTransactionAttribute - No relevant rollback rule found: applying default rules
I am using spring data jpa, studentservice.find(1234)
invokes //jparepository.findone()
method which runs in 1 transaction
studentservice.save(dto);
invokes //jparepository.save()
runs in another transaction which we can tell from the above log
Upvotes: 6
Views: 9409
Reputation: 637
In all likelihood it is more advisable that your Transaction boundary should be declared at the Service layer instead of in your Controllers.
For a more detailed explanation have a look here: Why we shouldn't make a Spring MVC controller @Transactional?
Upvotes: 3
Reputation:
By default the transaction is rolled back on RuntimeException
. Does your ApplicationException
extend RuntimeException
? If not, you may want to specify a rollbackFor
attribute of @Transactional
:
@Transactional(rollbackFor=Exception.class)
Upvotes: 2