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
What is this spring.jpa.open-in-view=true property in Spring Boot?
提问by Carlos Alberto
I saw spring.jpa.open-in-view=true
property in Spring Boot documentation for JPA configuration.
我spring.jpa.open-in-view=true
在 Spring Boot 文档中看到了 JPA 配置的属性。
- Is the
true
default 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
SessionFactory
instead ofEntityManagerFactory
? If yes, how can I tell it to allow me to useEntityManagerFactory
instead?
true
如果根本没有提供此属性的默认值吗?- 这真的有什么作用?我没有找到任何好的解释;
- 它会让你使用
SessionFactory
而不是EntityManagerFactory
吗?如果是,我怎么能告诉它允许我使用EntityManagerFactory
呢?
Thanks!
谢谢!
采纳答案by dunni
This property will register an OpenEntityManagerInViewInterceptor
, which registers an EntityManager
to the current thread, so you will have the same EntityManager
until the web request is finished. It has nothing to do with a Hibernate SessionFactory
etc.
此属性将注册一个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(在视图中打开会话)不是让业务层决定如何最好地获取视图层所需的所有关联,而是强制持久化上下文保持打开状态,以便视图层可以触发代理初始化,如图所示通过下图。
- The
OpenSessionInViewFilter
calls theopenSession
method of the underlyingSessionFactory
and obtains a newSession
. - The
Session
is bound to theTransactionSynchronizationManager
. - The
OpenSessionInViewFilter
calls thedoFilter
of thejavax.servlet.FilterChain
object reference and the request is further processed - The
DispatcherServlet
is called, and it routes the HTTP request to the underlyingPostController
. - The
PostController
calls thePostService
to get a list ofPost
entities. - The
PostService
opens a new transaction, and theHibernateTransactionManager
reuses the sameSession
that was opened by theOpenSessionInViewFilter
. - The
PostDAO
fetches the list ofPost
entities without initializing any lazy association. - The
PostService
commits the underlying transaction, but theSession
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 theSession
, 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 Connection
as 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 @BatchSize
for fetching associations in batches, and FetchMode.SUBSELECT
to 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.properties
configuration file, you have the following entry:
因此,请确保在application.properties
配置文件中包含以下条目:
spring.jpa.open-in-view=false
This will disable OSIV so that you can handle the LazyInitializationException
the 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 的更多详细信息,请查看这篇文章。