2016-01-06 146 views
4

使用Spring啓動1.3.1@RestController方法默認爲Transactional,爲什麼?

我不明白爲什麼@RestController默認爲Transactionnal。 我還沒有在文檔中發現任何內容。

實施例其推動這一事實,該方法findOne()在下面的控制器是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; 
    } 
} 

與的System.out.println(book.getAuthor()的getFirstName())的線;應該引起LazyInitiaizationFailure 但是在這裏它是成功的並且觸發了作者的選擇。 所以方法findOne似乎是事務性的。 使用eclipse調試器,我可以確定這是觸發互補選擇的這一行。 但爲什麼這種方法事務?

@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 

有什麼想法嗎?

如果它是一個功能,我想轉的吧...

回答

6

除了MirMasej答案,還有一兩件事:

  • 你有一個Web應用程序
  • 您使用JPA
:當滿足下列條件爲真春天開機後會自動註冊一個 OpenEntityManagerInViewInterceptor

這兩種情況對您而言都是正確的。這個攔截器讓實體管理器在整個請求期間保持打開狀態。自動配置發生在類JpaBaseConfiguration中。

如果你不希望這種行爲,可以將以下屬性添加到您的application.properties文件:

spring.jpa.open-in-view=false 

順便說一句。此行爲完全獨立於事務,它只與實體管理器的生命週期有關。如果兩個事務都具有相同的基礎實體管理器實例,則仍然可以有兩個單獨的事務並且沒有LazyInitializationException。

+0

好的謝謝你的解釋。很有幫助。 我試過預訂Dave.save(_book);然後bookDao.findOneById(_book.getId()); 在同一個處理程序方法中,並且findOne()不會命中數據庫,但會使用em緩存。所以它證明了你的觀點。同樣的em用於1rst save tx,然後用於findOne。但是第一個tx(保存)已經被提交 –

+0

順便說一句,你知道如何獲得它嗎? @PersistenceContext是否注入相同的em? –

+0

我會這麼認爲。 Spring Data JPA也使用這個註解來獲取實體管理器,而這個實體管理器也是綁定到請求的實體管理器。所以如果它適用於Spring Data,它應該適用於你的代碼。 – dunni

-1

一到一個關係總是預先抓取。通過方法名稱book.getAuthor().getFirstname()來判斷,book-> author和author-> firstName是這樣的關係。 LazyInitializationException只會出現在懶惰集合中。

+0

你一般都是對的,但在我的情況@ManyToOne(fetch = FetchType.LAZY),它解釋了行爲 –

相關問題