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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30549489/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 09:48:01  来源:igfitidea点击:

What is this spring.jpa.open-in-view=true property in Spring Boot?

javaspringjpaspring-bootspring-data

提问by Carlos Alberto

I saw spring.jpa.open-in-view=trueproperty in Spring Boot documentation for JPA configuration.

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

  • Is the truedefault value for this property if it's not provided at all?;
  • What does this really do? I did not find any good explaining for it;
  • Does it make you use SessionFactoryinstead of EntityManagerFactory? If yes, how can I tell it to allow me to use EntityManagerFactoryinstead?
  • true如果根本没有提供此属性的默认值吗?
  • 这真的有什么作用?我没有找到任何好的解释;
  • 它会让你使用SessionFactory而不是EntityManagerFactory吗?如果是,我怎么能告诉它允许我使用EntityManagerFactory呢?

Thanks!

谢谢!

采纳答案by dunni

This property will register an OpenEntityManagerInViewInterceptor, which registers an EntityManagerto the current thread, so you will have the same EntityManageruntil the web request is finished. It has nothing to do with a Hibernate SessionFactoryetc.

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

回答by Vlad Mihalcea

The OSIV Anti-Pattern

OSIV 反模式

Instead of letting the business layer decide how it's best to fetch all the associations that are needed by the View layer, OSIV (Open Session in View) forces the Persistence Context to stay open so that the View layer can trigger the Proxy initialization, as illustrated by the following diagram.

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

enter image description here

在此处输入图片说明

  • The OpenSessionInViewFiltercalls the openSessionmethod of the underlying SessionFactoryand obtains a new Session.
  • The Sessionis bound to the TransactionSynchronizationManager.
  • The OpenSessionInViewFiltercalls the doFilterof the javax.servlet.FilterChainobject reference and the request is further processed
  • The DispatcherServletis called, and it routes the HTTP request to the underlying PostController.
  • The PostControllercalls the PostServiceto get a list of Postentities.
  • The PostServiceopens a new transaction, and the HibernateTransactionManagerreuses the same Sessionthat was opened by the OpenSessionInViewFilter.
  • The PostDAOfetches the list of Postentities without initializing any lazy association.
  • The PostServicecommits the underlying transaction, but the Sessionis not closed because it was opened externally.
  • The DispatcherServletstarts rendering the UI, which, in turn, navigates the lazy associations and triggers their initialization.
  • The OpenSessionInViewFiltercan close the Session, and the underlying database connection is released as well.
  • 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,和底层数据库连接被释放为好。

At a first glance, this might not look like a terrible thing to do, but, once you view it from a database perspective, a series of flaws start to become more obvious.

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

The service layer opens and closes a database transaction, but afterward, there is no explicit transaction going on. For this reason, every additional statement issued from the UI rendering phase is executed in auto-commit mode. Auto-commit puts pressure on the database server because each statement must flush the transaction log to disk, therefore causing a lot of I/O traffic on the database side. One optimization would be to mark the Connectionas read-only which would allow the database server to avoid writing to the transaction log.

服务层打开和关闭一个数据库事务,但之后没有显式事务在进行。出于这个原因,从 UI 呈现阶段发出的每个附加语句都在自动提交模式下执行。自动提交给数据库服务器带来压力,因为每个语句都必须将事务日志刷新到磁盘,从而导致数据库端的大量 I/O 流量。一种优化是将 标记Connection为只读,这将允许数据库服务器避免写入事务日志。

There is no separation of concerns anymore because statements are generated both by the service layer and by the UI rendering process. Writing integration tests that assert the number of statements being generatedrequires going through all layers (web, service, DAO) while having the application deployed on a web container. Even when using an in-memory database (e.g. HSQLDB) and a lightweight web server (e.g. Jetty), these integration tests are going to be slower to execute than if layers were separated and the back-end integration tests used the database, while the front-end integration tests were mocking the service layer altogether.

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

The UI layer is limited to navigating associations which can, in turn, trigger N+1 query problems. Although Hibernate offers @BatchSizefor fetching associations in batches, and FetchMode.SUBSELECTto cope with this scenario, the annotations are affecting the default fetch plan, so they get applied to every business use case. For this reason, a data access layer query is much more suitable because it can be tailored to the current use case data fetch requirements.

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

Last but not least, the database connection is held throughout the UI rendering phase which increases connection lease time and limits the overall transaction throughput due to congestion on the database connection pool. The more the connection is held, the more other concurrent requests are going to wait to get a connection from the pool.

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

Spring Boot and OSIV

Spring Boot 和 OSIV

Unfortunately, OSIV (Open Session in View) is enabled by default in Spring Boot, and OSIV is really a bad idea from a performance and scalability perspective.

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

So, make sure that in the application.propertiesconfiguration file, you have the following entry:

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

spring.jpa.open-in-view=false

This will disable OSIV so that you can handle the LazyInitializationExceptionthe right way.

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

Starting with version 2.0, Spring Boot issues a warning when OSIVis enabled by default, so you can discover this problem long before it affects a production system.

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

For more details about OSIV, check out this article.

有关 OSIV 的更多详细信息,请查看这篇文章