18

使用 Spring Boot 1.3.1

我不明白为什么 @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 调试器,我可以确定确实是这一行触发了互补选择。但是为什么那个方法是 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

任何想法 ?

如果它是一个功能,我想将其关闭...

4

3 回答 3

24

除了 MirMasej 的回答之外,还有一件事:Spring Boot 会OpenEntityManagerInViewInterceptor在满足以下条件时自动注册一个:

  • 你有一个网络应用程序
  • 你使用 JPA

在您的情况下,这两个条件都成立。这个拦截器让实体管理器在整个请求期间保持打开状态。自动配置发生在类中JpaBaseConfiguration

如果您不希望这种行为,您可以将以下属性添加到您的 application.properties 文件中:

spring.jpa.open-in-view=false

顺便提一句。这种行为完全独立于事务,它只与实体管理器的生命周期有关。如果两个事务具有相同的底层实体管理器实例,您仍然可以有两个单独的事务并且没有 LazyInitializationException。

于 2016-01-06T21:29:03.983 回答
1

@dunni 的答案绝对出色且有效。在我的情况下,它会惩罚性能,在从@Controller调用@Service的方法时, @ Transactional处理只读JPA 操作,另一方面,从@WebServlet调用相同的方法处理它的速度要快两倍。但是从@Controller设置spring.jpa.open-in-view=false的处理速度与从@WebServlet一样快。

但除此之外,您可以统一执行以下操作,并以这种方式使用@Transactional注释从@Controller调用的方法,例如:

@GetMapping("/test")
@Transactional(propagation = Propagation.NEVER, readOnly = true)
public void test()
于 2021-12-16T13:00:17.533 回答
0

一对一的关系总是很受欢迎。从方法名来看book.getAuthor().getFirstname(), book->author 和 author->firstName 就是这样的关系。 LazyInitializationException只会发生在惰性集合中。

于 2016-01-06T20:02:14.477 回答