• springmvc事务回滚失效


    转载:http://blog.csdn.net/z69183787/article/details/37819831

    前文提到,最新换了框架,新项目用SpringMVC + Spring JdbcTemplate。搭框架时,发现了一个事务无法正常回滚的问题,记录如下:

    首先展示问题:

    Spring applicationContext.xml配置:

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
     
     
    1.          
    2. <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">  
    3.     <property name="jndiName">  
    4.         <value>java:comp/env/jdbc/will</value>  
    5.     </property>  
    6. </bean>   
    7.       
    8. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">  
    9.     <property name="dataSource" ref="dataSource" />  
    10. </bean>  
    11.   
    12. <bean id="txManager"  
    13.     class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
    14.     <property name="dataSource" ref="dataSource" />  
    15. </bean>  
    16.   
    17. <!-- 事务控制   -->  
    18. <tx:annotation-driven transaction-manager="txManager" />  

    Spring mvc.dispatcher.xml配置:

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
     
     
    1. <!-- 自动扫描的包名 -->    
    2. <context:component-scan base-package="com.will" >   
    3. </context:component-scan>  
    4.   
    5. <!-- 默认的注解映射的支持 -->  
    6. <mvc:annotation-driven />  
    7.   
    8. <!-- 对静态资源文件的访问  -->    
    9. <mvc:default-servlet-handler/>    
    10.     
    11.       
    12. <!-- 拦截器    
    13. <mvc:interceptors>    
    14.     <bean class="com.will.mvc.MyInteceptor" />    
    15. </mvc:interceptors>   
    16. -->   
    17.   
    18. <!-- 视图解释类 -->   
    19. <bean id="viewResolver"    
    20.     class="org.springframework.web.servlet.view.UrlBasedViewResolver">    
    21.     <property name="viewClass"  value="org.springframework.web.servlet.view.JstlView" />    
    22.     <property name="prefix" value="/WEB-INF/pages/" />    
    23.     <property name="suffix" value=".jsp" />    
    24. </bean>     


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

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
     
    1. @Transactional  
    2. public boolean save(Person person)  
    3. {  
    4.    for(int id: new int[]{2,3})  
    5.     {  
    6.         personDao.del(id);  
    7.         int j = 1/0;  
    8.     }                  
    9.      
    10.     return false;  
    11. }  

    本以为大功告成,在运行save方法时,由于1/0 抛出 java.lang.ArithmeticException: / by zero  RuntimeException,导致事务回归。However,no way! So crazy~

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

    需要在 applicationContext.xml增加:

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
     
     
    1. <context:component-scan base-package="com.will">   
    2.     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />   
    3. </context:component-scan>  


    在 Spring mvc.dispatcher.xml增加:

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
     
     
    1. <context:component-scan base-package="com.will" >   
    2.     <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />   
    3.     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />    
    4. </context:component-scan>  

    由于web.xml中配置:

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
     
     
    1. <context-param>  
    2.     <param-name>contextConfigLocation</param-name>  
    3.     <param-value>  
    4.              classpath:applicationContext.xml  
    5.     </param-value>  
    6. </context-param>  
    7. <listener>  
    8.     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
    9. </listener>  
    10. <servlet>  
    11.     <servlet-name>dispatcher</servlet-name>  
    12.     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
    13.     <init-param>  
    14.          <param-name>contextConfigLocation</param-name>  
    15.          <param-value>classpath*:/mvc_dispatcher_servlet.xml</param-value>  
    16.     </init-param>  
    17.     <load-on-startup>1</load-on-startup>  
    18. </servlet>  
    19. <servlet-mapping>  
    20.     <servlet-name>dispatcher</servlet-name>  
    21.     <url-pattern>*.do</url-pattern>  
    22. </servlet-mapping>  

    Spring容器优先加载由ServletContextListener(对应applicationContext.xml)产生的父容器,而SpringMVC(对应mvc_dispatcher_servlet.xml)产生的是子容器。子容器Controller进行扫描装配时装配的@Service注解的实例是没有经过事务加强处理,即没有事务处理能力的Service,而父容器进行初始化的Service是保证事务的增强处理能力的。如果不在子容器中将Service exclude掉,此时得到的将是原样的无事务处理能力的Service。

    ( update 2014.05.27  今天看见一种说法:key word =双亲上下文。不使用ContextLoaderListener监听器来加载spring的配置,改用DispatcherServlet来加载spring的配置,不要双亲上下文,只使用一个DispatcherServlet就不会出现上述问题。笔者这里未测过这个办法,因为我自己的业务需要一个extends ContextLoaderListener的selfListener,有兴趣的朋友可以自己测试下这个说法,并欢迎把测试的结果与我交流 :) )

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

    在 applicationContext.xml增加:

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
     
     
    1. <context:component-scan base-package="com.will">   
    2. </context:component-scan>  


    在 Spring mvc.dispatcher.xml增加:

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
     
     
      1. <context:component-scan base-package="com.will" >      
      2.     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />    
      3. </context:component-scan>  

    经过如上配置,可以发现事务控制部分,可以回滚。

    另外:也不是必须运行时异常才会回滚。@Transactional  (rollbackfor=Exception.class) 这样设置的话,任何异常都可以回滚。

  • 相关阅读:
    STL--sort源码分析
    进程和线程的区别
    static 关键字 静态成员变量及静态成员函数
    二叉树遍历总结 先序、中序、后续、广度、深度
    C++用new和不用new创建类对象区别
    传输层--TCP和UDP的区别
    传输层的作用
    微信商户/H5支付申请 被拒原因:网站存在不实内容或不安全信息
    Oracle本地网络服务名配置
    存储过程常用技巧
  • 原文地址:https://www.cnblogs.com/fanguangdexiaoyuer/p/5380573.html
Copyright © 2020-2023  润新知