木一 发表于 2016-11-27 12:14:57

springmvc mybatis 事务不回滚(转)

  转自:http://blog.csdn.net/will_awoke/article/details/12002705
前文提到,最新换了框架,新项目用SpringMVC + Spring JdbcTemplate。搭框架时,发现了一个事务无法正常回滚的问题,记录如下:
首先展示问题:
Spring applicationContext.xml配置:
 
 view plaincopy



[*]         
[*]<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配置:
 
 view plaincopy



[*]<!-- 自动扫描的包名 -->    
[*]<context:component-scan base-package="com.will" >   
[*]</context:component-scan>  
[*]  
[*]<!-- 默认的注解映射的支持 -->  
[*]<mvc:annotation-driven />  
[*]  
[*]<!-- 对静态资源文件的访问  -->    
[*]<mvc:default-servlet-handler/>    
[*]    
[*]      
[*]<!-- 拦截器    
[*]<mvc:interceptors>    
[*]    <bean class="com.will.mvc.MyInteceptor" />    
[*]</mvc:interceptors>   
[*]-->   
[*]  
[*]<!-- 视图解释类 -->   
[*]<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:
 
 
 view plaincopy



[*]@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,导致事务回归。However,no way! So crazy~
查了下,发现Spring MVC对于事务配置比较讲究,需要额外的配置。解决办法如下:
  
 
 
需要在 applicationContext.xml增加:
 
 view plaincopy



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

  
在 Spring mvc.dispatcher.xml增加:
 
 
 view plaincopy



[*]<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中配置:
 
 view plaincopy



[*]<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>  
[*]    </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。
 
经过以上分析,故可以优化上述配置:
 
在 applicationContext.xml增加:
 
 view plaincopy



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

  
在 Spring mvc.dispatcher.xml增加:
 
 
 view plaincopy



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

 
经过如上配置,可以发现事务控制部分的日志如下:
 
 view plaincopy



[*]2013-09-25 09:53:13,031  DEBUG  - Adding transactional method 'save' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''  
[*]2013-09-25 09:53:13,037  DEBUG  - Returning cached instance of singleton bean 'txManager'  
[*]2013-09-25 09:53:13,050  DEBUG  - Creating new transaction with name : PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''  
[*]2013-09-25 09:53:13,313  DEBUG  - Acquired Connection useUnicode=true&characterEncoding=UTF-8, UserName=root@localhost, MySQL-AB JDBC Driver] for JDBC transaction  
[*]2013-09-25 09:53:13,323  DEBUG  - Switching JDBC Connection useUnicode=true&characterEncoding=UTF-8, UserName=root@localhost, MySQL-AB JDBC Driver] to manual commit  
[*]2013-09-25 09:53:13,327  DEBUG  - Executing prepared SQL update  
[*]2013-09-25 09:53:13,328  DEBUG  - Executing prepared SQL statement id=?]  
[*]2013-09-25 09:53:13,348  DEBUG  - SQL update affected 1 rows  
[*]2013-09-25 09:53:13,363  DEBUG  - Initiating transaction rollback  
[*]2013-09-25 09:53:13,364  DEBUG  - Rolling back JDBC transaction on Connection useUnicode=true&characterEncoding=UTF-8, UserName=root@localhost, MySQL-AB JDBC Driver]  
[*]2013-09-25 09:53:13,377  DEBUG  - Releasing JDBC Connection useUnicode=true&characterEncoding=UTF-8, UserName=root@localhost, MySQL-AB JDBC Driver] after transaction  
[*]2013-09-25 09:53:13,378  DEBUG  - Returning JDBC Connection to DataSource  

  
在2013-09-25 09:53:13,363处进行了rollback。
 
  
 
页: [1]
查看完整版本: springmvc mybatis 事务不回滚(转)