Spring Boot中的这个spring.jpa.open-in-view=true property是什么?

2022-08-31 05:46:22

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

  • 如果根本没有提供此属性,则此属性的默认值是否为默认值?true
  • 这到底有什么作用?我没有找到任何好的解释;
  • 它是否使您使用而不是?如果是,我怎么能告诉它允许我使用?SessionFactoryEntityManagerFactoryEntityManagerFactory

谢谢!


答案 1

OSIV 反模式

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

OSIV Anti-Pattern

  • 调用基础的方法并获取新的 .OpenSessionInViewFilteropenSessionSessionFactorySession
  • 绑定到事务同步管理器Session
  • 进一步处理对象引用的调用和请求OpenSessionInViewFilterdoFilterjavax.servlet.FilterChain
  • 调度程序Servlet被调用,它将HTTP请求路由到底层的。PostController
  • 调用 以获取实体列表。PostControllerPostServicePost
  • 将打开一个新事务,并重用 由 打开的相同事务。PostServiceHibernateTransactionManagerSessionOpenSessionInViewFilter
  • 获取实体列表而不初始化任何惰性关联。PostDAOPost
  • 提交基础事务,但未关闭,因为它是在外部打开的。PostServiceSession
  • 开始呈现 UI,而 UI 又导航惰性关联并触发其初始化。DispatcherServlet
  • 可以关闭 ,并且底层数据库连接也会被释放。OpenSessionInViewFilterSession

乍一看,这看起来可能不是一件可怕的事情,但是,一旦你从数据库的角度来看待它,一系列的缺陷就会开始变得更加明显。

服务层打开和关闭数据库事务,但之后没有显式事务发生。因此,从 UI 呈现阶段发出的每个附加语句都将在自动提交模式下执行。自动提交会给数据库服务器带来压力,因为每个事务在结束时都会发出一个提交,这可能会触发事务日志刷新到磁盘。一种优化是将 标记为只读,这将允许数据库服务器避免写入事务日志。Connection

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

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

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

弹簧靴和 OSIV

不幸的是,OSIV(在视图中打开会话)在Spring Boot中默认启用,从性能和可伸缩性的角度来看,OSIV确实是一个坏主意。

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

spring.jpa.open-in-view=false

这将禁用OSIV,以便您可以以正确的方式处理。LazyInitializationException

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


答案 2

此属性将注册 一个 ,它将 注册到当前线程,因此在 Web 请求完成之前,您将拥有相同的内容。它与休眠等无关。OpenEntityManagerInViewInterceptorEntityManagerEntityManagerSessionFactory


推荐