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

lb3vh1jj  于 12个月前  发布在  Spring
关注(0)|答案(4)|浏览(130)

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

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

谢谢你,谢谢

svmlkihl

svmlkihl1#

OSIV反模式

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

  • OpenSessionInViewFilter调用底层SessionFactoryopenSession方法并获得新的Session
  • Session绑定到TransactionSynchronizationManager
  • OpenSessionInViewFilter调用javax.servlet.FilterChain对象引用的doFilter,并进一步处理请求
  • 调用DispatcherServlet,它将HTTP请求路由到底层PostController
  • PostController调用PostService以获取Post实体的列表。
  • PostService打开一个新事务,HibernateTransactionManager重用OpenSessionInViewFilter打开的同一个Session
  • PostDAO获取Post实体的列表,而不初始化任何惰性关联。
  • PostService提交底层事务,但Session没有关闭,因为它是在外部打开的。
  • DispatcherServlet开始呈现UI,这反过来又导航惰性关联并触发它们的初始化。
  • OpenSessionInViewFilter可以关闭Session,并且底层数据库连接也被释放。

乍一看,这可能看起来并不是一件可怕的事情,但是,一旦从数据库的Angular 来看,一系列的缺陷开始变得更加明显。
服务层打开和关闭一个数据库事务,但是之后,没有显式的事务继续进行。因此,UI呈现阶段发出的每个附加语句都以自动提交模式执行。自动提交会给数据库服务器带来压力,因为每个事务都在结束时发出一个提交,这可能会触发事务日志刷新到磁盘。一个优化是将Connection标记为只读,这将允许数据库服务器避免写入事务日志。
不再存在关注点分离,因为语句是由服务层和UI呈现过程生成的。编写Assert生成的语句数量的集成测试需要遍历所有层(Web、服务、DAO),同时将应用程序部署在Web容器上。即使使用内存数据库(例如,HSQLDB)和轻量级Web服务器(例如,Jetty),这些集成测试的执行速度将比层分离、后端集成测试使用数据库、而前端集成测试完全模拟服务层的情况慢。
UI层仅限于导航关联,这反过来又会触发N+1个查询问题。尽管Hibernate提供了@BatchSize来批量获取关联,并提供了FetchMode.SUBSELECT来科普这种情况,但注解会影响默认的获取计划,因此它们会应用于每个业务用例。出于这个原因,数据访问层查询更适合,因为它可以根据当前用例的数据获取需求进行调整。
最后但并非最不重要的一点是,数据库连接在整个UI呈现阶段保持,这会增加连接租用时间,并由于数据库连接池上的拥塞而限制整体事务吞吐量。连接保持得越多,等待从池中获取连接的其他并发请求就越多。

Sping Boot 和OSIV

不幸的是,从性能和可伸缩性的Angular 来看,OSIV (Open Session in View) is enabled by default in Spring Boot和OSIV确实是一个坏主意。
因此,请确保在application.properties配置文件中有以下条目:

spring.jpa.open-in-view=false

这将禁用OSIV,以便您可以正确地处理LazyInitializationException
从2.0版开始,默认情况下启用Sping Boot issues a warning when OSIV,因此您可以在影响生产系统之前发现此问题。

fsi0uk1n

fsi0uk1n2#

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

nzk0hqpo

nzk0hqpo3#

可能是晚了,但我正试图挖掘更多关于关闭它的含义与。上,我发现这篇文章很有用spring-open-session-in-view
希望这能帮助到一些人…

j2cgzkjk

j2cgzkjk4#

在视图中打开(对于OSIV)的一个原因是为了开发人员的生产力,因为它消除了显式加载所有延迟加载属性的需要。
https://stackoverflow.com/a/76864391/242042展示了一种执行显式加载的方法。关闭open-in-view以防止LazyInitializationException。
但是,它会使执行JPA操作的每个控制器Map都启动一个事务,因此可能会导致数据库连接耗尽。
另一种方法(也被认为是一种反模式)是告诉Hibernate允许通过添加延迟加载而不使用事务。

spring:
  jpa:
    properties:
      hibernate.enable_lazy_load_no_trans: true

就开发人员的生产力而言,这是相同的,但就性能而言,这可能会稍微好一点,因为它只会在对象需要延迟加载的情况下启动事务。
显然,正确的方法是执行join fetch@EntityGraph,但这增加了开发人员的复杂性。但这可能是之后的性能改进。
在我看来,使用hibernate.enable_lazy_load_no_trans并关闭open-in-view,但找到触发enable_lazy_load_no_trans功能的地方(ideally via a log)并纠正它。

相关问题