2016-01-06 191 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),它解释了行为 –