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

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

谢谢!


当前回答

可能有点晚了,但我试图挖掘更多关于关闭和打开的含义,我发现这篇文章很有用

希望这能帮助到一些人…

其他回答

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

OSIV反模式

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

The OpenSessionInViewFilter calls the openSession method of the underlying SessionFactory and obtains a new Session. The Session is bound to the TransactionSynchronizationManager. The OpenSessionInViewFilter calls the doFilter of the javax.servlet.FilterChain object reference and the request is further processed The DispatcherServlet is called, and it routes the HTTP request to the underlying PostController. The PostController calls the PostService to get a list of Post entities. The PostService opens a new transaction, and the HibernateTransactionManager reuses the same Session that was opened by the OpenSessionInViewFilter. The PostDAO fetches the list of Post entities without initializing any lazy association. The PostService commits the underlying transaction, but the Session is not closed because it was opened externally. The DispatcherServlet starts rendering the UI, which, in turn, navigates the lazy associations and triggers their initialization. The OpenSessionInViewFilter can close the Session, and the underlying database connection is released as well.

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

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 transaction issues a commit at end, which can trigger a transaction log flush to disk. One optimization would be to mark the Connection as read-only which would allow the database server to avoid writing to the transaction log.

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 generated requires 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 webserver (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层仅限于导航关联,这反过来会触发N+1个查询问题。尽管Hibernate提供了用于批量获取关联的@BatchSize,以及FetchMode。SUBSELECT为了应对这种情况,注释会影响默认的获取计划,因此它们会应用到每个业务用例。由于这个原因,数据访问层查询更合适,因为它可以根据当前用例数据获取需求进行定制。

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

Spring Boot和OSIV

不幸的是,在Spring Boot中默认启用了OSIV (Open Session in View),从性能和可伸缩性的角度来看,OSIV确实是一个糟糕的主意。

确保在应用程序中。属性配置文件,您有以下条目:

spring.jpa.open-in-view=false

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

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

可能有点晚了,但我试图挖掘更多关于关闭和打开的含义,我发现这篇文章很有用

希望这能帮助到一些人…