Spring Boot中的spring.jpa.open-in-view = true属性是什么?


121

spring.jpa.open-in-view=true在Spring Boot文档中看到了有关JPA配置的属性。

  • true如果根本没有提供此属性的默认值?
  • 这到底是做什么的?我没有找到任何很好的解释。
  • 它使您SessionFactory代替使用EntityManagerFactory吗?如果是,我如何告诉它允许我使用它EntityManagerFactory

谢谢!

Answers:


52

该属性将注册一个OpenEntityManagerInViewInterceptor,将一个注册EntityManager到当前线程,因此您将具有相同的属性,EntityManager直到Web请求完成。它与Hibernate SessionFactory等无关。


目前,我具有过滤器OpenEntityManagerInViewFilter来控制EntityManager,直到完成Web请求为止。您所说的“ OpenEntityManagerInViewInterceptor”拦截器是否与“ OpenEntityManagerInViewFilter”相同?它们之间有什么区别?因此,我在Spring Boot的servlet上下文中没有更多的此过滤器了吗?
卡洛斯·阿尔贝托2015年

1
仅当您在Spring中使用DispatcherServlet时,拦截器才有效(因为拦截器是一种Spring机制)。过滤器可以映射到所有配置的servlet(我们在其中一个应用程序中将其用于FacesServlet)。因此,如果仅使用DispatcherServlet,则可以添加属性并删除过滤器,否则使用过滤器。
dunni 2015年

298

OSIV反模式

OSIV(视图中的打开会话)并没有让业务层决定如何最好地获取视图层所需的所有关联,而是强制持久性上下文保持打开状态,以便视图层可以触发代理初始化,如图所示通过下图。

在此处输入图片说明

  • OpenSessionInViewFilter调用openSession底层的方法SessionFactory,并获得新的Session
  • Session被绑定到TransactionSynchronizationManager
  • OpenSessionInViewFilter调用doFilter的的javax.servlet.FilterChain对象引用和所述请求被进一步处理
  • DispatcherServlet被调用,并将HTTP请求路由到底层PostController
  • PostController呼叫PostService拿到名单Post的实体。
  • PostService打开一个新的事务,而HibernateTransactionManager重用相同Session,是由打开的OpenSessionInViewFilter
  • 在不初始化任何惰性关联的情况下PostDAO获取Post实体列表。
  • PostService提交将提交基础事务,但是Session未关闭,因为它是在外部打开的。
  • DispatcherServlet开始渲染的UI,这反过来,导航懒惰协会,并触发其初始化。
  • OpenSessionInViewFilter可以关闭Session,和底层数据库连接被释放为好。

乍看起来,这似乎并不可怕,但是,从数据库的角度来看,一系列缺陷变得更加明显。

服务层打开和关闭数据库事务,但是此后,没有任何显式事务在进行。因此,从UI渲染阶段发出的所有其他语句都将在自动提交模式下执行。自动提交给数据库服务器带来了压力,因为每个语句都必须将事务日志刷新到磁盘,因此在数据库侧会导致大量I / O通信。一种优化是将标记Connection为只读,这将允许数据库服务器避免写入事务日志。

由于服务层和UI呈现过程都生成了语句,因此不再存在关注点分离。编写断言所生成语句数量的集成测试需要在将应用程序部署在Web容器上的同时遍历所有层(Web,服务,DAO)。即使在使用内存数据库(例如HSQLDB)和轻量级Web服务器(例如Jetty)时,这些集成测试的执行速度也要比分离层和后端集成测试使用数据库的速度要慢。前端集成测试完全模拟了服务层。

UI层仅限于导航关联,而关联又可以触发N + 1个查询问题。尽管Hibernate提供@BatchSize了批量获取关联的功能,并且FetchMode.SUBSELECT为了应对这种情况,但注释会影响默认的获取计划,因此它们会应用于每个业务用例。因此,数据访问层查询非常适合,因为它可以针对当前用例数据获取要求进行定制。

最后但并非最不重要的一点是,数据库连接会在整个UI呈现阶段保持不变,这会增加连接租用时间并由于数据库连接池上的拥塞而限制总体事务吞吐量。保持的连接越多,等待从池中获取连接的其他并发请求就越多。

Spring Boot和OSIV

不幸的是,在Spring Boot中默认启用了OSIV(视图中的Open Session)从性能和可伸缩性的角度来看,OSIV实际上不是一个好主意

因此,请确保在application.properties配置文件中具有以下条目:

spring.jpa.open-in-view=false

这将禁用OSIV这样就可以处理LazyInitializationException的正确方法

从版本2.0开始,默认情况下启用OSIV时,Spring Boot会发出警告,因此您可以在此问题影响生产系统很长时间之前就发现它。

有关OSIV的更多详细信息,请查看本文


14
现在有一个警告正在记录。
Vlad Mihalcea

这一般适用于Spring,还是仅适用于Spring Boot?是否可以通过@Configuration注释的类而不是设置属性来禁用它?
Gordon

2
它仅适用于Spring Boot。在标准Spring中,您明确选择要使用的bean或是否需要Web过滤器,例如OSIV。我不知道您是否可以通过一些注释禁用它。我只知道配置设置。
Vlad Mihalcea

这不是反模式。它确实对性能有影响,有时是负面的,在很多情况下通常是中立的,并且在很多情况下都是积极的:如果您确实想开始一个懒惰的关系,则不必在所有情况下都进行查询并可以在需要时通过使用视野开阔来避免这种情况。
ymajoros

5
根据Wikipedia的说法,“反模式是通常对无效的重复出现的问题的普遍反应,并且可能产生适得其反的风险”。这就是View中的Open Session。
Vlad Mihalcea
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.