spring web使用hibernate的事务控制报错

       最近学习了一下spring web,在处理事务时报如下错误,网上找了很久都没找到直接原因,这个问题比较典型,这里根据网上找的和自己的理解做一下记录

问题

DEBUG 2013-07-30 15:58:24,444 org.springframework.web.servlet.FrameworkServlet: Could not complete request

org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)

原因分析

       applicationContext.xml中配置有下面的内容时,此txManager是一个AOP切面,会对此ContextLoaderListener上下文进行代理处理,而ContextLoaderListener和DispatcherServlet是父子上下文关系,父上下文不能访问子上下文,从而不能对applicationContext-servlet.xml中的bean进行AOP事务处理,或者可以理解为DispatcherServlet子上下文创建service对象时,没有创建父上下文ContextLoaderListener的AOP,即AOP只能作用于同一层的BeanFactory中

<!-- 事务 -->

<bean id="txManager"

class="org.springframework.orm.hibernate3.HibernateTransactionManager">

<property name="sessionFactory" ref="sessionFactory" />

<property name="dataSource" ref="dataSource" />

</bean>

<tx:annotation-driven transaction-manager="txManager" />

      这也就是为什么将上面的配置移动到applicationContext-servlet.xml中后,就可以进行事务处理了,txManager的AOP范围变为DispatchServlet子上下文了

解决办法

解决的办法是,让ContextLoaderListener扫描service,不要让DispatcherServlet扫描到service,这样所有创建的service都来自ContextLoaderListener父上下文,从而可以事务控制AOP了

解决的配置:

在applicationContext.xml增加下面内容(网上写的是要加下面的内容,但加不加不影响最终结果,可能会影响部分效率):

    <!-- 扫描除web层外的bean,以避免其他层事务失效 -->

<context:component-scan base-package="com.myproject">

<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>

</context:component-scan>

在applicationContext-servlet.xml中增加下面内容:

<!-- 让注解的bean工作起来,该配置已包含context:annotation-config的功能 -->

<context:component-scan base-package="com.myproject" >

<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/><!--网上写的是要加下面的内容,但加不加不影响最终结果,可能会影响部分效率-->

<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" /><!--这里非常关键-->

</context:component-scan>

web.xml的配置:<!-- 初始化spring -->

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>

/WEB-INF/config/spring/applicationContext.xml,

/WEB-INF/config/spring/applicationContext-dao.xml,

/WEB-INF/config/spring/applicationContext-securitycode.xml

</param-value>

</context-param>

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

<!-- 初始化spring mvc -->

<servlet>

<servlet-name>spring</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>

<param-name>contextConfigLocation</param-name>

<param-value>

      /WEB-INF/config/spring/applicationContext-servlet.xml

</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

相关推荐