论坛首页 Java企业应用论坛

由OpenSessionInViewFilter报错引出的spring3.0事务配置问题及解决办法

浏览 10426 次
精华帖 (1) :: 良好帖 (3) :: 新手帖 (0) :: 隐藏帖 (2)
作者 正文
   发表时间:2010-08-15   最后修改:2010-08-16
开发环境

IDE: eclipse3.4
FrameWork: spring3.0 + spring mvc 3.0 + hibernate 3.2
Server: Tomcat 6.0

使用 OpenSessionInViewFilter的原因

引用
Hibernate 允许对关联对象、属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Session 范围之内进行。如果 Service 层返回一个启用了延迟加载功能的领域对象给 Web 层,当 Web 层访问到那些需要延迟加载的数据时,由于加载领域对象的 Hibernate Session 已经关闭,这些导致延迟加载数据的访问异常。而Spring为我们提供的OpenSessionInViewFilter过滤器为我们很好的解决了这个问题。OpenSessionInViewFilter的主要功能是使每个请求过程绑定一个 Hibernate Session,即使最初的事务已经完成了,也可以在 Web 层进行延迟加载的操作。OpenSessionInViewFilter 过滤器将 Hibernate Session 绑定到请求线程中,它将自动被 Spring 的事务管理器探测到。


在Service层执行插入,删除及数据更新操作时会包以下错误
引用
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition


报错原因:
看过OpenSessionInViewFilter以后就知道,OpenSessionInViewFilter的getSession方法中会对session的flushMode设定一个默认为NEVER的值

解决办法有两个:
1:继承OpenSessionInViewFilter,并覆盖getSession,设施flushMode 为AUTO
2:通过spring的事务管理Hibernate的sessionFactory,对不同的数据操作作事务的隔离及限制

因为反正都要用到spring作事务管理,所以我在项目中采用了第二种方法

spring2.5以后就支持annotation配置了,到了3.0配置更加简化方便了,但对于新手来说,如果不懂具体的spring运作原理,很容易犯错误,并且在报错之后很难发现错误原因。

在此特将spring的配置方法写出来,并经过实例测试,是可以通过并正常运行的。希望对在这方面遇到问题的朋友有帮助,spring的基于annotation请不明白的朋友在网上查看相关文档。

主要配置文件有两个

app-config.xml 配置数据源,hibernate,事务等
mvc-config.xml 配置spring mvc的 controller,viewResolver,messageConvert等

本文主要涉及 app-config.xml的配置

首先通过以下配置,自动扫描com包内作了annotation注解的类,并实例化(至于里面为什么会有个exclude-filter请看文章的后面)
  <context:component-scan base-package="com">  
       <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
    </context:component-scan>


hibernate及数据源的配置
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
	   <property name="dataSource" ref="dataSource"/>
	   <property name="packagesToScan" value="com"/>

        	   
	   
	   <property name="hibernateProperties">
			<props>	

			    
			    
			    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>		    
				<!--  <prop key="hibernate.dialect">org.hibernate.dialect.sql</prop>-->
				<!-- <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop> -->
				
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
				<prop key="hibernate.cache.use_query_cache">true</prop>
				

				<prop key="hibernate.hbm2ddl.auto">update</prop>
				<prop key="hibernate.format_sql">true</prop>
				<prop key="hibernate.use_sql_comments">true</prop>

				<!--  
				<prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider</prop>
				<prop key="hibernate.search.default.indexBase">/WEB-INF/indexes</prop>-->
			</props>
	    </property>
	 </bean>


配置transactionManager管理事务
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" autowire="byName"/>


接下来是 自动化事务
<tx:annotation-driven/>

如果前面配置的事务id不是"transactionManager",比如id="txManager",则应该如下配置
<tx:annotation-driven transaction-manager="txManager"/>


这里需要注意的问题,看过spring的参考手册的朋友都会这样配置
<context:component-scan base-package="com">

因为省事,一句话可以自动把com包低下的所有带annotation注解的类都实例化并配好了,但如果这样简单的配置会导致刚才spring的事务配置失效
原因:
实例化@Controller类时,Spring会自动把关联的@Service(此@Service已做了@Transaction事务注解)类实例化,此时事务并未生效,导致@Transaction注解无效,事务未被注册

因此需要把@Controller和其它的@Service,@Components,@Reposity等分开实例化,在事务生效后,并且其它组件都实例化完成后,@Controller最后实例化,app-config.xml和mvc-config.xml的配置分别如下

app-config.xml
   <!-- 扫描com及子包,自动实例化带@注释的实例,这里排除@Controller,所有controller的实例化在 mvc-config中完成 -->
   <context:component-scan base-package="com">  
       <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
    </context:component-scan
>

mvc-config.xml(注意里面的注释)
	 <!-- 扫描com及子包,自动实例化带@controller注释的实例,
	      由于实例化controller时会对controller关联的Service类一同实例化,所以这里需要排除@Service 
	 -->
	<context:component-scan base-package="com">
	   <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	   <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
	</context:component-scan>



此时在带@Service注解的类中添加@Transactional标签就会其作用了,例如
@Service("articleService")
@Transactional
public class ArticleService extends GenericService<Article, Long> {
       
        @Autowired
	private ArticleDao articleDao;

        @Transactional(readOnly=true)
        public List<Article> getArticles(){
          /*...*/
        }
        
        @Transactional(propagation=Propagation.REQUIRED)
        public void saveArticle(long id){
            /*..*/
        }


}

更多事务注解的方式请参考spring3.0 reference

这这样需要对每个Service的方法都要做类似的注解,多了会很麻烦,也难管理维护。

下面通过spring的aop对事务进行自动化管理,配置如下
	<!-- 配置aop 切入点 和事务访问策略 -->   
	<aop:config>
	  <aop:pointcut id="serviceOperation" expression="execution(* com.*.service..*Service.*(..))"/> 
      <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/>
	</aop:config>
	
	
	<tx:advice id="txAdvice" > 
		<tx:attributes>
			<tx:method name="del*" propagation="REQUIRED"/>
			<tx:method name="save*" propagation="REQUIRED"/>
			<tx:method name="update*" propagation="REQUIRED"/>
			<tx:method name="add*" propagation="REQUIRED"/>
			<tx:method name="create*" propagation="REQUIRED"/>
			<tx:method name="get*" read-only="true"/>
			<tx:method name="*"/>
		</tx:attributes>
	</tx:advice>  
 

注意
1这部分代码要放在<tx:annotation-driven/>的上面,否则tx:advice不起作用
2<tx:advice id="txAdvice" > 如果前面配置的事务id不是"transactionManager",比如id="txManager",则应该修改为 <tx:advice id="txAdvice" transaction-manager="txManager" >


app-config.xml的整个配置如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans	
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-3.0.xsd
		http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
   
     
    
   <!-- 扫描com及子包,自动实例化带@注释的实例,这里排除@Controller,所有controller的实例化在 mvc-config中完成 -->
   <context:component-scan base-package="com">  
       <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
    </context:component-scan>
    
          
   
   <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>/WEB-INF/prop/database.properties</value>
            </list>
        </property>
    </bean> 

    <!-- JNDI DataSource for J2EE environments  user c3p0-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
  		<property name="driverClass"><value>${jdbc.driverClass}</value></property>
  		<property name="jdbcUrl"><value>${jdbc.jdbcUrl}</value></property>		
  		<property name="user"><value>${jdbc.user}</value></property>
  		<property name="password"><value>${jdbc.password}</value></property>
  		<property name="minPoolSize"><value>${jdbc.minPoolSize}</value></property>
  		<property name="maxPoolSize"><value>${jdbc.maxPoolSize}</value></property>
  		<property name="maxIdleTime"><value>${jdbc.maxIdleTime}</value></property>
	</bean>
    
    
     <!--  hibernate.hbm2ddl.auto参数说明
				validate           加载hibernate时,验证创建数据库表结构
 				create             每次加载hibernate,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。
 				create-drop        加载hibernate时创建,退出是删除表结构
  				update             加载hibernate自动更新数据库结构
  				none               不更新数据库结构
  	  -->    
	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
	   <property name="dataSource" ref="dataSource"/>
	   <property name="packagesToScan" value="com"/>

        	   
	   
	   <property name="hibernateProperties">
			<props>	

			    
			    
			    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>		    
				<!--  <prop key="hibernate.dialect">org.hibernate.dialect.sql</prop>-->
				<!-- <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop> -->
				
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
				<prop key="hibernate.cache.use_query_cache">true</prop>
				

				<prop key="hibernate.hbm2ddl.auto">update</prop>
				<prop key="hibernate.format_sql">true</prop>
				<prop key="hibernate.use_sql_comments">true</prop>

				<!--  
				<prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider</prop>
				<prop key="hibernate.search.default.indexBase">/WEB-INF/indexes</prop>-->
			</props>
	    </property>
	 </bean>    
    
    <!-- 配置hibernate事务 -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" autowire="byName"/>

   

    
    
	<!-- 配置aop 切入点 和事务访问策略 -->   
	<aop:config>
	  <aop:pointcut id="serviceOperation" expression="execution(* com.*.service..*Service.*(..))"/> 
      <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/>
	</aop:config>
	
	
	<tx:advice id="txAdvice" > 
		<tx:attributes>
			<tx:method name="del*" propagation="REQUIRED"/>
			<tx:method name="save*" propagation="REQUIRED"/>
			<tx:method name="update*" propagation="REQUIRED"/>
			<tx:method name="add*" propagation="REQUIRED"/>
			<tx:method name="create*" propagation="REQUIRED"/>
			<tx:method name="get*" read-only="true"/>
			<tx:method name="*"/>
		</tx:attributes>
	</tx:advice>    
    
    <!-- tx:annotation 自动配置事务,注意这个标签必需放在tx:advice下面,否则不起作用 -->
    <tx:annotation-driven/>
    
        
	<!-- Application Message Bundle -->
	<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
		<property name="basename" value="/WEB-INF/messages/messages" />
		<property name="cacheSeconds" value="0" />
	</bean>

	<!-- Configures Spring MVC 
	<import resource="mvc-config.xml" />
	-->
	

</beans>
















   发表时间:2010-08-15  
非常感谢 解决了最近困扰的springmvc 事务不起作用的问题!
0 请登录后投票
   发表时间:2010-08-15   最后修改:2010-08-15
最关键的一段话存在语病和错别字:
引用
web 容器在扫描包含@Service或@Components的类并包含@Transaction是,此时@Transaction并为完成,导致事务未被注册。

因此需要把@Controller和其它的@Service,@components,@Reposity等标签分开实例化,controller放到最后实例化,app-config.xml和mvc-config.xml的配置分别入戏

看不懂。
0 请登录后投票
   发表时间:2010-08-16  
daquan198163 写道
最关键的一段话存在语病和错别字:
引用
web 容器在扫描包含@Service或@Components的类并包含@Transaction是,此时@Transaction并为完成,导致事务未被注册。

因此需要把@Controller和其它的@Service,@components,@Reposity等标签分开实例化,controller放到最后实例化,app-config.xml和mvc-config.xml的配置分别入戏

看不懂。


谢谢提醒,已改正。

那句话的意思是指 如果简单的用<context:component-scan base-package="com">让spring自动扫描注册组件,在注册@Service或@Components时,事务配置还没起作用,这些组件就已经实例化了,最后导致spring的容器中的事务管理无效
0 请登录后投票
   发表时间:2010-08-16  
楼主,能否把mvc-config.xml也完整发出来看看呢?或者有个完整的例子那是最好了 谢谢哈
0 请登录后投票
   发表时间:2010-08-16  
事务控制在service边界 即使用了hibernateinview,一对多的加载总是出现懒加载的问题 请问楼主是如何解决的?
如果将事务边界在control层,这个配置该如何呢?
0 请登录后投票
   发表时间:2010-08-16   最后修改:2010-08-16
qq528 写道
楼主,能否把mvc-config.xml也完整发出来看看呢?或者有个完整的例子那是最好了 谢谢哈



这里是mvc-config.xml的全部配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context" 
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">


	
	 <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> 
		<property name="messageConverters">
			<list> 
				<ref bean="stringHttpMessageConverter"/> 
				<ref bean="jacksonMessageConverter"/>
     		</list>
   		</property>
   		
   		<property name="webBindingInitializer">
          <bean class="com.common.web.BaseBindingInitializer" /> 
        </property>
	  </bean>

   <bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter"/>
   <bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>	
	
	<!-- Configures the @Controller programming model -->
	<mvc:annotation-driven/>
		
	 
	 
	 <!-- 扫描com及子包,自动实例化带@controller注释的实例,
	      由于实例化controller时会对controller关联的Service类一同实例化,所以这里需要排除@Service 
	 -->
	<context:component-scan base-package="com">
	   <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	   <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
	</context:component-scan>

	<!-- Forwards requests to the "/" resource to the "welcome" view -->
	<mvc:view-controller path="/" view-name="welcome"/>

	<!-- Configures Handler Interceptors -->	
	<mvc:interceptors>
		<!-- Changes the locale when a 'locale' request parameter is sent; e.g. /?locale=de -->
		<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
	</mvc:interceptors>

	<!-- Saves a locale change using a cookie -->
	<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" />

	<!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/"/>
		<property name="suffix" value=".jsp"/>
	</bean>
	
	
	
	

</beans>



这是web.xml的基本配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>spring-security-base</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  
  
   <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
          /WEB-INF/spring/security.xml
          /WEB-INF/spring/app-config.xml
        </param-value>
    </context-param>
    

    <!-- spring security 过滤器链 -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    
    
    
    
	<!-- Reads request input using UTF-8 encoding -->
	<filter>
		<filter-name>characterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>

	<filter-mapping>
		<filter-name>characterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>  
	
	
	
	
	
	<!-- for restful style 注意要放在 characterEncodingFilter 否则可能引起不必要的乱码-->
 	<filter> 
 		<filter-name>httpMethodFilter</filter-name> 
 		<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
	</filter>
	<filter-mapping> 
		<filter-name>httpMethodFilter</filter-name> 
		<url-pattern>/*</url-pattern>
		
	</filter-mapping>	
  
    
    <!--OpenSessionInViewFilter 作用,防止hibernate lazy-load 引起的不在同一session的报错  -->
    <filter>
        <filter-name>hibernateFilter</filter-name> 
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hibernateFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>  
    
    
    
    
      
	<!-- Enables clean URLs with JSP views e.g. /welcome instead of /app/welcome 
	     注意:
	     过滤器执行顺序是按web.xml中的各过滤器的位置顺序执行的
	     将其它过滤器放在此过滤器的前面,否则由于url重写,会导致其它过滤器过滤的url失效
	-->
	<filter>
		<filter-name>UrlRewriteFilter</filter-name>
		<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
		<!--   <init-param>  
                <param-name>logLevel</param-name>  
                <param-value>DEBUG</param-value>  
        </init-param>
        -->    
	</filter>

	<filter-mapping>
		<filter-name>UrlRewriteFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>    	  
  
  

  
  

    
    
  
 
  
  	<!-- Handles all requests into the application -->
	<servlet>
		<servlet-name>springMVCBase</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	    <init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>
				/WEB-INF/spring/mvc-config.xml
			</param-value>
		</init-param>
		
		<load-on-startup>2</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>springMVCBase</servlet-name>
		<url-pattern>/app/*</url-pattern>
	</servlet-mapping>  
	
	
 
	
  
	
</web-app>


很抱歉,由于我的项目里还有很多其它的依赖,又没有用maven做管理,现在放出来可能也无法运行。你可以用svn把spring的的在线例子下载下来看。我的配置大部分是参考里面的 mvc-base 和 mvc-ajax这两个例子,在其基础上增加了spring security和事务管理等

这是spirng samples的 svn地址 https://src.springframework.org/svn/spring-samples/





0 请登录后投票
   发表时间:2010-08-16  
qq528 写道
事务控制在service边界 即使用了hibernateinview,一对多的加载总是出现懒加载的问题 请问楼主是如何解决的?
如果将事务边界在control层,这个配置该如何呢?



用OpenSessionInViewFilter就是为了解决延迟加载session不同步的问题,我测试了延迟加载,是可以顺利在jsp页面调用的
这是jsp页面里的测试代码

                           <ul>
                               <c:forEach var="article" items="${group.articles}">
                                  <li>${article.title}</li>
                               </c:forEach>
                             </ul>


我对spring aop和事务控制的理解也很肤浅,在我看来,无论你把@Transcational放在哪,最终都是通过HibernateSessionFactory起作用,放在service是为了保证里面有多个数据更新时,如果失败可以保证整体数据的回滚,当然是否正确的回滚还需再测试,我会在测试后把结果贴出来
0 请登录后投票
   发表时间:2010-08-16  
aixinnature 写道
qq528 写道
事务控制在service边界 即使用了hibernateinview,一对多的加载总是出现懒加载的问题 请问楼主是如何解决的?
如果将事务边界在control层,这个配置该如何呢?



用OpenSessionInViewFilter就是为了解决延迟加载session不同步的问题,我测试了延迟加载,是可以顺利在jsp页面调用的
这是jsp页面里的测试代码

                           <ul>
                               <c:forEach var="article" items="${group.articles}">
                                  <li>${article.title}</li>
                               </c:forEach>
                             </ul>


我对spring aop和事务控制的理解也很肤浅,在我看来,无论你把@Transcational放在哪,最终都是通过HibernateSessionFactory起作用,放在service是为了保证里面有多个数据更新时,如果失败可以保证整体数据的回滚,当然是否正确的回滚还需再测试,我会在测试后把结果贴出来

我的意思是在control中如果使用了如下的情况,延迟加载是失败的 该如何解决?
control:
login 方法:
1、User user=userservice.findbyNameAndpassword();//此处用事务获取了实体
方法执行完后,事务管理会关闭session
2、紧接着如果再用user.getUserGroup().getRules()则报延迟加载错误的问题了。

所以想把事务加载在control层,该如何操作呢?
0 请登录后投票
   发表时间:2010-08-16   最后修改:2010-08-16

qq528 写道

事务控制在service边界 即使用了hibernateinview,一对多的加载总是出现懒加载的问题 请问楼主是如何解决的?如果将事务边界在control层,这个配置该如何呢?

 

 

事务控制放在service层,是为了对我们的业务做完善的事务控制,前提是你的业务逻辑都在service中实现。如果这样的话,不需要在controller层配置事务。另外,为了解决延迟加载的问题,你将事务控制放在controller层中也不起作用,原因有2:

  1. 延迟加载时在spring mvc渲染view的时候产生的,你的controller代码还没开始渲染。
  2. 延迟加载的目的主要是读,而一般需要控制事务的时候主要是保证业务的提交或回滚,所以为了延迟加载而将事务的控制放在controller层也不合适。

另外,可以考虑用OpenSessionInViewInterceptor替换OpenSessionInViewFilter。性能应该好一些的。

0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics