spring.jpa.open-in-view=true在Spring Boot文档中看到了有关JPA配置的属性。
spring.jpa.open-in-view=true
true
SessionFactory
EntityManagerFactory
The OSIV Anti-Pattern
OSIV(视图中的打开会话)没有让业务层决定如何最好地获取视图层所需的所有关联,而是强制持久性上下文保持打开状态,以便视图层可以触发代理初始化,如图所示通过下图。
OpenSessionInViewFilter
openSession
Session
TransactionSynchronizationManager
doFilter
javax.servlet.FilterChain
DispatcherServlet
PostController
PostService
HibernateTransactionManager
乍看起来,这似乎并不可怕,但是,从数据库的角度来看,一系列缺陷变得更加明显。
服务层打开和关闭数据库事务,但是此后,没有任何显式事务在进行。因此,在自动提交模式下执行从UI渲染阶段发出的所有其他语句。自动提交给数据库服务器带来了压力,因为每个语句都必须将事务日志刷新到磁盘,因此在数据库侧会导致大量I / O通信。一种优化是将标记Connection为只读,这将允许数据库服务器避免写入事务日志。
由于服务层和UI呈现过程都生成了语句,因此不再存在关注点分离。编写断言要生成的语句数量的集成测试需要在将应用程序部署在Web容器上的同时遍历所有层(Web,服务,DAO)。即使在使用内存数据库(例如HSQLDB)和轻量级Web服务器(例如Jetty)时,这些集成测试的执行速度也要比分离层和后端集成测试使用数据库的速度慢。前端集成测试完全模拟了服务层。
UI层仅限于导航关联,这又会触发N + 1查询问题。尽管Hibernate提供@BatchSize了批量获取关联的功能,并且FetchMode.SUBSELECT为了应对这种情况,但注释会影响默认的获取计划,因此它们会应用于每个业务用例。因此,数据访问层查询非常适合,因为它可以针对当前用例数据获取要求进行定制。
最后但并非最不重要的一点是,数据库连接在整个UI呈现阶段均保持不变,这会增加连接租用时间并由于数据库连接池上的拥塞而限制总体事务吞吐量。保持的连接越多,等待从池中获取连接的其他并发请求越多。
Spring Boot and OSIV
不幸的是,在Spring Boot中默认启用了OSIV(视图中的Open Session),从性能和可伸缩性的角度来看,OSIV确实不是一个好主意。
因此,请确保在application.properties配置文件中具有以下条目:
application.properties
spring.jpa.open-in-view=false
这将禁用OSIV这样就可以处理LazyInitializationException的正确方法。
LazyInitializationException
从2.0版开始,默认情况下启用OSIV时,Spring Boot会发出警告,因此你可以在此问题影响生产系统很长时间之前就发现它。