带有@Transactional注释的Spring OpenSessionInViewFilter
这与Spring OpenSessionInViewFilter
有关,在服务层使用@Transactional
注释。
我经历了这么多的堆栈溢出post,但仍然困惑我是否应该使用OpenSessionInViewFilter
,以避免LazyInitializationException
如果有人帮我找到以下查询的答案,这将是很大的帮助。
- 在具有复杂模式的应用程序中使用
OpenSessionInViewFilter
是不好的做法。 - 使用此filter可能会导致
N+1
问题 - 如果我们使用
OpenSessionInViewFilter
,是否意味着不需要@Transactional
?
下面是我的Spring配置文件
classpath:hibernate.cfg.xml org.hibernate.cfg.AnnotationConfiguration ${jdbc.dialect} true <!-- create -->
OpenSessionInView
是一个servletfilter,而不仅仅是打开一个hibernate会话,并将它存储在SessionHolder
用于为请求提供服务的线程。 打开此会话后,当您在请求的呈现阶段使用它时,hibernate可以读取Lazy初始化集合和对象。 调用SessionFactory.getCurrentSession()
时可以访问此会话。
但是,OpenSessionInView只是打开会话,它不会开始任何事务。 打开会话后,您可以从数据库中读取对象,但是,如果要在事务中执行某些操作,则需要使用@Transactional
注释或其他机制来根据需要划分事务的开始和结束。
然后回答问题:
在具有复杂模式的应用程序中使用OpenSessionInViewFilter是不好的做法。
如果你需要避免使用LazyInitializationException并且重载只是打开新的Hibernate Session并在每个请求的请求结束时关闭它,这是一个很好的做法。
使用此filter可能会导致N + 1问题
我在许多项目中使用此filter,并没有造成任何问题。
如果我们使用OpenSessionInViewFilter,是否意味着不需要@Transactional?
不可以。你只在线程的SessionHolder中打开了一个Hibernate Session,但是如果你需要Transactions,你需要放置@Transactional
。
在这里扔掉我的0.02c(并扩展Fernando Rincon的优秀答案 ):
您不应该仅仅因为需要绕过LazyInitializationException
而使用OpenSessionInView
filter。 它只会给你的系统增加另一层混乱和复杂性。 您应该从系统设计中确切地知道您需要在前端访问集合的位置。 从那里开始,很容易(根据我的经验)构建一个控制器方法来调用服务方法来检索你的集合更合乎逻辑。
但是,如果你有另一个问题,使用OpenSessionInView
filter解决,并作为一个愉快的副作用,然后你打开一个会话,那么我没有看到使用它来访问你的集合的危害。 但是,我要说如果你使用OpenSessionInView
在一个地方获取一个集合对象,你应该在其他地方重构你的代码来做同样的事情,因为用于获取集合的策略在你的应用程序中是标准化的。
权衡此重构的成本与编写控制器和服务方法的成本,以确定您是否应该使用OpenSessionInView
filter。
OpenSessionInViewFilter是一个servletfilter,它将hibernate会话绑定到http请求,对于所有数据库操作,事务性和非事务性,同一个hibernate会话用于给定的http请求。 这会将db层暴露给Web层,使其成为反模式。
我的经验是,当我们想要对java对象进行更改并且不希望它们反映在数据库中时,这会使代码难以调试。 由于hibernate会话始终处于打开状态,因此它希望刷新数据库中的数据。
仅当JS基本rest服务存在且其间没有服务层时,才应使用此方法。
OpenSessionInViewFilter的典型使用模式是某些实体被延迟加载,但在视图呈现阶段,视图需要此实体的一些属性,这些属性最初未加载,因此需要从数据库中获取此数据。 现在,通常在Web应用程序的服务层中进行事务划分,因此在视图呈现发生时,视图正在使用分离的实体,这会在访问卸载的属性时导致LazyInitializationException
。
从这个urlhttps://developer.jboss.org/wiki/OpenSessionInView :
问题
典型的Web应用程序中的一个常见问题是在操作的主要逻辑完成之后呈现视图,因此,Hibernate会话已经关闭并且数据库事务已经结束。 如果访问已在JSP(或任何其他视图呈现机制)内的Session中加载的分离对象,则可能会遇到未加载的集合或未初始化的代理。 您得到的exception是:LazyInitializationException:会话已关闭(或非常类似的消息)。 当然,这是可以预料的,毕竟你已经结束了你的工作单元。第一种解决方案是打开另一个工作单元来渲染视图。 这很容易做到,但通常不是正确的方法。 渲染已完成操作的视图应该在第一个工作单元内,而不是单独的工作单元。 在双层系统中,具有动作执行,通过会话进行数据访问以及在同一虚拟机中呈现视图的解决方案是在会话呈现之前保持会话处于打开状态。
作为替代方案,请考虑使用视图所需的适当数据量加载实体。 这可以通过使用DTO投影来完成。 本文列出了使用Open Session In View模式的一些缺点: https : //vladmihalcea.com/the-open-session-in-view-anti-pattern/