带有@Transactional注释的Spring OpenSessionInViewFilter

时间:2014-05-26 21:23:02

标签: java spring hibernate spring-transactions

这是关于Spring OpenSessionInViewFilter在服务层使用@Transactional注释。

我经历了这么多堆栈溢出帖子,但仍然困惑我是否应该OpenSessionInViewFilter使用LazyInitializationException以避免OpenSessionInViewFilter 如果有人帮我找到以下问题的答案,那将会很有帮助。

  • 在应用程序中使用N+1是不好的做法 有复杂的架构。
  • 使用此过滤器可能会导致OpenSessionInViewFilter问题
  • 如果我们使用@Transactional,是否意味着<context:component-scan base-package="com.test"/> <context:annotation-config/> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="resources/messages" /> <property name="defaultEncoding" value="UTF-8" /> </bean> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="/WEB-INF/jdbc.properties" /> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" /> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation"> <value>classpath:hibernate.cfg.xml</value> </property> <property name="configurationClass"> <value>org.hibernate.cfg.AnnotationConfiguration</value> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${jdbc.dialect}</prop> <prop key="hibernate.show_sql">true</prop> <!-- <prop key="hibernate.hbm2ddl.auto">create</prop> --> </props> </property> </bean> <tx:annotation-driven /> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> 不是必需的?

下面是我的Spring配置文件

{{1}}

4 个答案:

答案 0 :(得分:11)

OpenSessionInView是一个servlet过滤器,而不仅仅是打开一个hibernate会话并将其存储在SessionHolder中,用于为请求提供服务的线程。打开此会话后,当您在请求的呈现阶段使用它时,hibernate可以读取Lazy初始化集合和对象。调用SessionFactory.getCurrentSession()时可以访问此会话。

但是,OpenSessionInView只是打开会话,它不会开始任何交易。打开会话后,您可以从数据库中读取对象,但是,如果要在事务中执行某些操作,则需要@Transactional注释或其他机制来根据需要划分事务的开始和结束。

然后回答问题:

  

在具有复杂架构的应用程序中使用OpenSessionInViewFilter是不好的做法。

如果你需要避免使用LazyInitializationException并且重载只是打开新的Hibernate Session并在每个请求的请求结束时关闭它,这是一个很好的做法。

  

使用此过滤器可能会导致N + 1问题

我在很多项目中使用这个过滤器而不会引起任何问题。

  

如果我们使用的是OpenSessionInViewFilter,是否表示不需要@Transactional?

没有。您只在线程的SessionHolder中打开了Hibernate会话,但如果您需要事务,则需要放置@Transactional

答案 1 :(得分:3)

在这里投掷我的0.02c(并在Fernando Rincon's excellent answer上扩展):

您不应该使用OpenSessionInView过滤器 ,因为您需要绕过LazyInitializationException。它只会给你的系统增加另一层混乱和复杂性。您应该从系统设计中准确地知道您需要在前端访问集合的位置。从那里开始,很容易(根据我的经验)构建一个控制器方法来调用服务方法来检索你的集合更合乎逻辑。

但是,如果你有另一个问题,使用OpenSessionInView过滤器解决了,并且作为一个愉快的副作用,你打开了一个会话,那么我没有看到使用它来访问你的收藏的危害。但是,我要说如果你使用OpenSessionInView在一个地方获取一个集合对象,你应该在其他地方重构你的代码来做同样的事情,因为用于获取集合的策略是标准化的整个申请。

将这个重构的成本与编写控制器的成本相比较。服务方法,以确定您是否应该使用OpenSessionInView过滤器。

答案 2 :(得分:2)

OpenSessionInViewFilter是一个servlet过滤器,它将hibernate会话绑定到http请求,对于所有数据库操作,事务性和非事务性,同一个hibernate会话用于给定的http请求。这会将db层暴露给Web层,使其成为反模式。

我的经验是,当我们想要对java对象进行更改并且不希望这些对象反映在数据库中时,这会使代码难以调试。由于hibernate会话始终处于打开状态,因此它希望刷新数据库中的数据。

仅当JS基础休息服务没有服务层时才应该使用它。

答案 3 :(得分:1)

OpenSessionInViewFilter的典型使用模式是某些实体被延迟加载,但在视图呈现阶段,视图需要此实体的一些属性,这些属性最初未加载,因此需要从数据库中获取此数据。现在,通常在Web应用程序的服务层中进行事务划分,因此在视图呈现发生时,视图正在使用分离的实体,在访问卸载的属性时会导致LazyInitializationException。 / p>

来自此网址https://developer.jboss.org/wiki/OpenSessionInView

  

问题
  典型的Web应用程序中的一个常见问题是在操作的主要逻辑完成之后呈现视图,因此,Hibernate会话已经关闭并且数据库事务已经结束。如果访问已在JSP(或任何其他视图呈现机制)内的Session中加载的分离对象,则可能会遇到未加载的集合或未初始化的代理。您得到的异常是:LazyInitializationException:会话已关闭(或非常类似的消息)。当然,毕竟你已经结束了你的工作单元,这是可以预期的。

     

第一个解决方案是打开另一个工作单元来渲染视图。这很容易做到,但通常不是正确的方法。渲染已完成操作的视图应该位于第一个工作单元内,而不是单独的单元。在双层系统中,具有动作执行,通过会话进行数据访问以及在同一虚拟机中呈现视图的解决方案是在会话呈现之前保持会话处于打开状态。

作为替代方案,请考虑使用视图所需的适当数据量加载实体。这可以通过使用DTO投影来完成。本文列出了使用Open Session In View模式的一些缺点:https://vladmihalcea.com/the-open-session-in-view-anti-pattern/

相关问题