Chandana Reddy
Chandana Reddy

Reputation: 63

spring boot @controller @transactional doesnt work

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

Answers (2)

zwessels
zwessels

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

user178982
user178982

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

Related Questions