Spring MVC @Transactional注解方式事务失效的解决办法

本文介绍了一种SpringMVC环境下配置事务回滚的方法。通过调整applicationContext.xml和Springmvc.dispatcher.xml配置,确保@Service注解的方法能正确执行事务回滚。
项目用SpringMVC + Spring JdbcTemplate。搭框架时,发现了一个事务无法正常回滚的问题,记录如下:

首先展示问题:

Spring applicationContext.xml配置:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">  
    <property name="jndiName">  
        <value>java:comp/env/jdbc/will</value>  
    </property>  
</bean>   
      
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">  
    <property name="dataSource" ref="dataSource" />  
</bean>  
  
<bean id="txManager"  
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
    <property name="dataSource" ref="dataSource" />  
</bean>  
  
<!-- 事务控制   -->  
<tx:annotation-driven transaction-manager="txManager" />  

Spring mvc.dispatcher.xml(springMvc.xml)配置:

<!-- 自动扫描的包名 -->    
<context:component-scan base-package="com.will" >   
</context:component-scan>  
  
<!-- 默认的注解映射的支持 -->  
<mvc:annotation-driven />  
  
<!-- 对静态资源文件的访问  -->    
<mvc:default-servlet-handler/>    
  
<!-- 视图解释类 -->   
<bean id="viewResolver"    
    class="org.springframework.web.servlet.view.UrlBasedViewResolver">    
    <property name="viewClass"  value="org.springframework.web.servlet.view.JstlView" />    
    <property name="prefix" value="/WEB-INF/pages/" />    
    <property name="suffix" value=".jsp" />    
</bean>   

然后在Service层模拟了一个事务回滚的method case:

    @Transactional  
    public boolean save(Person person)  
    {  
       for(int id: new int[]{2,3})  
        {  
            personDao.del(id);  
            int j = 1/0;  
        }                  
         
        return false;  
    }  


本以为大功告成,在运行save方法时,由于1/0 抛出 java.lang.ArithmeticException: / by zero  RuntimeException,导致事务回归,但是不生效!

查了下,发现Spring MVC对于事务配置比较讲究,需要额外的配置。解决办法如下:
需要在 applicationContext.xml增加:

<context:component-scan base-package="com.will">   
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />   
</context:component-scan> 

在 Spring mvc.dispatcher.xml(springMvc.xml)增加:

    <context:component-scan base-package="com.will" >   
        <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中配置:

    <context-param>  
        <param-name>contextConfigLocation</param-name>  
        <param-value>  
                 classpath:applicationContext.xml  
        </param-value>  
    </context-param>  
    <listener>  
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
    </listener>  
    <servlet>  
        <servlet-name>dispatcher</servlet-name>  
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
        <init-param>  
             <param-name>contextConfigLocation</param-name>  
             <param-value>classpath*:/mvc_dispatcher_servlet.xml</param-value>  
             <!-- <param-value>classpath*:/springMvc.xml</param-value> -->
        </init-param>  
        <load-on-startup>1</load-on-startup>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>dispatcher</servlet-name>  
        <url-pattern>*.do</url-pattern>  
    </servlet-mapping>  

Spring容器优先加载由ServletContextListener(对应applicationContext.xml)产生的父容器,而SpringMVC(对应mvc_dispatcher_servlet.xml)产生的是子容器。子容器Controller进行扫描装配时装配的@Service注解的实例是没有经过事务加强处理,即没有事务处理能力的Service,而父容器进行初始化的Service是保证事务的增强处理能力的。如果不在子容器中将Service exclude掉,此时得到的将是原样的无事务处理能力的Service,因为在多上下文的情况下,如果同一个bean被定义两次,后面一个优先


经过以上分析,故可以优化上述配置

在 applicationContext.xml增加:

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

在 Spring mvc.dispatcher.xml(springMvc.xml)增加:
    <context:component-scan base-package="com.will" >      
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />    
    </context:component-scan>  

经过如上配置,成功进行了rollback。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值