我在Sping Boot 文档中看到了JPA配置的spring.jpa.open-in-view=true属性。
spring.jpa.open-in-view=true
true
SessionFactory
EntityManagerFactory
谢谢你,谢谢
svmlkihl1#
OSIV(在视图中打开会话)强制持久性上下文保持打开状态,以便视图层可以触发代理初始化,而不是让业务层决定如何最好地获取视图层所需的所有关联,如下图所示。
OpenSessionInViewFilter
openSession
Session
TransactionSynchronizationManager
javax.servlet.FilterChain
doFilter
DispatcherServlet
PostController
PostService
Post
HibernateTransactionManager
PostDAO
乍一看,这可能看起来并不是一件可怕的事情,但是,一旦从数据库的Angular 来看,一系列的缺陷开始变得更加明显。服务层打开和关闭一个数据库事务,但是之后,没有显式的事务继续进行。因此,UI呈现阶段发出的每个附加语句都以自动提交模式执行。自动提交会给数据库服务器带来压力,因为每个事务都在结束时发出一个提交,这可能会触发事务日志刷新到磁盘。一个优化是将Connection标记为只读,这将允许数据库服务器避免写入事务日志。不再存在关注点分离,因为语句是由服务层和UI呈现过程生成的。编写Assert生成的语句数量的集成测试需要遍历所有层(Web、服务、DAO),同时将应用程序部署在Web容器上。即使使用内存数据库(例如,HSQLDB)和轻量级Web服务器(例如,Jetty),这些集成测试的执行速度将比层分离、后端集成测试使用数据库、而前端集成测试完全模拟服务层的情况慢。UI层仅限于导航关联,这反过来又会触发N+1个查询问题。尽管Hibernate提供了@BatchSize来批量获取关联,并提供了FetchMode.SUBSELECT来科普这种情况,但注解会影响默认的获取计划,因此它们会应用于每个业务用例。出于这个原因,数据访问层查询更适合,因为它可以根据当前用例的数据获取需求进行调整。最后但并非最不重要的一点是,数据库连接在整个UI呈现阶段保持,这会增加连接租用时间,并由于数据库连接池上的拥塞而限制整体事务吞吐量。连接保持得越多,等待从池中获取连接的其他并发请求就越多。
Connection
@BatchSize
FetchMode.SUBSELECT
不幸的是,从性能和可伸缩性的Angular 来看,OSIV (Open Session in View) is enabled by default in Spring Boot和OSIV确实是一个坏主意。因此,请确保在application.properties配置文件中有以下条目:
application.properties
spring.jpa.open-in-view=false
这将禁用OSIV,以便您可以正确地处理LazyInitializationException。从2.0版开始,默认情况下启用Sping Boot issues a warning when OSIV,因此您可以在影响生产系统之前发现此问题。
LazyInitializationException
fsi0uk1n2#
此属性将注册一个OpenEntityManagerInViewInterceptor,它将EntityManager注册到当前线程,因此在Web请求完成之前,您将拥有相同的EntityManager。它与Hibernate SessionFactory等无关。
OpenEntityManagerInViewInterceptor
EntityManager
nzk0hqpo3#
可能是晚了,但我正试图挖掘更多关于关闭它的含义与。上,我发现这篇文章很有用spring-open-session-in-view希望这能帮助到一些人…
j2cgzkjk4#
在视图中打开(对于OSIV)的一个原因是为了开发人员的生产力,因为它消除了显式加载所有延迟加载属性的需要。https://stackoverflow.com/a/76864391/242042展示了一种执行显式加载的方法。关闭open-in-view以防止LazyInitializationException。但是,它会使执行JPA操作的每个控制器Map都启动一个事务,因此可能会导致数据库连接耗尽。另一种方法(也被认为是一种反模式)是告诉Hibernate允许通过添加延迟加载而不使用事务。
open-in-view
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)并纠正它。
join fetch
@EntityGraph
hibernate.enable_lazy_load_no_trans
enable_lazy_load_no_trans
4条答案
按热度按时间svmlkihl1#
OSIV反模式
OSIV(在视图中打开会话)强制持久性上下文保持打开状态,以便视图层可以触发代理初始化,而不是让业务层决定如何最好地获取视图层所需的所有关联,如下图所示。
OpenSessionInViewFilter
调用底层SessionFactory
的openSession
方法并获得新的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
配置文件中有以下条目:这将禁用OSIV,以便您可以正确地处理
LazyInitializationException
。从2.0版开始,默认情况下启用Sping Boot issues a warning when OSIV,因此您可以在影响生产系统之前发现此问题。
fsi0uk1n2#
此属性将注册一个
OpenEntityManagerInViewInterceptor
,它将EntityManager
注册到当前线程,因此在Web请求完成之前,您将拥有相同的EntityManager
。它与HibernateSessionFactory
等无关。nzk0hqpo3#
可能是晚了,但我正试图挖掘更多关于关闭它的含义与。上,我发现这篇文章很有用spring-open-session-in-view
希望这能帮助到一些人…
j2cgzkjk4#
在视图中打开(对于OSIV)的一个原因是为了开发人员的生产力,因为它消除了显式加载所有延迟加载属性的需要。
https://stackoverflow.com/a/76864391/242042展示了一种执行显式加载的方法。关闭
open-in-view
以防止LazyInitializationException。但是,它会使执行JPA操作的每个控制器Map都启动一个事务,因此可能会导致数据库连接耗尽。
另一种方法(也被认为是一种反模式)是告诉Hibernate允许通过添加延迟加载而不使用事务。
就开发人员的生产力而言,这是相同的,但就性能而言,这可能会稍微好一点,因为它只会在对象需要延迟加载的情况下启动事务。
显然,正确的方法是执行
join fetch
或@EntityGraph
,但这增加了开发人员的复杂性。但这可能是之后的性能改进。在我看来,使用
hibernate.enable_lazy_load_no_trans
并关闭open-in-view
,但找到触发enable_lazy_load_no_trans
功能的地方(ideally via a log)并纠正它。