spring web使用hibernate的事务控制报错
问题
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>