Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@RestController methods seem to be Transactional by default, Why?

Using Spring boot 1.3.1

I don't understand why @RestController are Transactionnal by default. I haven't found anything saying so in the docs.

Example which pushes this fact that the method findOne() in the controller below is Transactionnal:

@RestController
@RequestMapping("/books")
public class BookController {

    @RequestMapping("/{id}")
    public Book findOne(@PathVariable Long id) {
        Book book = this.bookDao.findOneBookById(id);
        // following line
        // => triggers a select author0_.id as id1_0_0_ etc... // where author0_.id=?
        System.out.println(book.getAuthor().getFirstname()); 
        return book;
    }
}

The line with the System.out.println(book.getAuthor().getFirstname()); should raise a LazyInitiaizationFailure BUT here it is successful and trigger the select of an an Author. So the method findOne seems to be transactionnal. With the eclipse debugger I can be sure that it is really this line that triggers the complementary select. But Why is that method transactionnal ?

@Configuration
@ComponentScan(basePackageClasses = _Controller.class)
@Import(BusinessConfig.class)
public class WebConfig extends WebMvcConfigurerAdapter {
   // ... here the conf to setup Jackson Hibernate4Module
}

@Configuration
@EnableAutoConfiguration
@EnableTransactionManagement
@EntityScan(basePackageClasses = _Model.class)
@ComponentScan(basePackageClasses = { _Dao.class })
public class BusinessConfig {
}

@SpringBootApplication
public class BookstoreStartForWebEmbedded {

    public static void main(String[] args) {
        SpringApplication.run(BookstoreStartForWebEmbedded.class, args);
    }

}

libs : 
spring-boot-starter 1.3.1.RELEASE
spring-boot-starter-test : 1.3.1.RELEASE
spring-boot-starter-valisation : 1.3.1.RELEASE
spring-boot-starter-web : 1.3.1.RELEASE
spring-boot-starter-data-jpa : 1.3.1.RELEASE
postgresql: 9.4-1206-jdbc41
querydsl-jps:3.7.0
jackson-annotations:2.6.4
jackson-datatype-hibernate4:2.6.4

any idea ?

If it is a feature, i would like to switch it off...

like image 382
Gauthier Peel Avatar asked Jan 06 '16 19:01

Gauthier Peel


People also ask

Which of the following are the default @transactional settings?

The default @Transactional settings are: The propagation setting is PROPAGATION_REQUIRED. The isolation level is ISOLATION_DEFAULT. The transaction is read/write.

Why do we use @transactional annotation?

The @Transactional annotation makes use of the attributes rollbackFor or rollbackForClassName to rollback the transactions, and the attributes noRollbackFor or noRollbackForClassName to avoid rollback on listed exceptions. The default rollback behavior in the declarative approach will rollback on runtime exceptions.

Should controllers be transactional?

The controller can be made @Transactional , but indeed it's a common recommendation to only make the service layer transactional (the persistence layer should not be transactional either). The reason for this is not technical feasibility, but separation of concerns.

Why @transactional is used in Spring boot?

So when you annotate a method with @Transactional , Spring dynamically creates a proxy that implements the same interface(s) as the class you're annotating. And when clients make calls into your object, the calls are intercepted and the behaviors injected via the proxy mechanism.


1 Answers

In addition to MirMasej answers, there is one more thing: Spring Boot will automatically register an OpenEntityManagerInViewInterceptor when the following conditions are true:

  • you have a web application
  • you use JPA

Both conditions are true in your case. This interceptor holds the entity manager open for the whole duration of a request. The auto configuration occurs in the class JpaBaseConfiguration.

If you don't want that behaviour, you can add the following property to your application.properties file:

spring.jpa.open-in-view=false

Btw. this behaviour is completely independent of transactions, it's only related to the lifecycle of the entity manager. You can still have two separate transactions and no LazyInitializationException, if both transactions have the same underlying entity manager instance.

like image 115
dunni Avatar answered Dec 15 '22 05:12

dunni