转自:http://blog.csdn.net/will_awoke/article/details/12002705
前文提到,最新换了框架,新项目用SpringMVC + Spring JdbcTemplate。搭框架时,发现了一个事务无法正常回滚的问题,记录如下:
首先展示问题:
Spring applicationContext.xml配置:
[html] 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配置:
[html] 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:
[java] 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增加:
[html] 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增加:
[html] 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中配置:
[html] 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增加:
[html] view plaincopy
< context:component-scan base-package = "com.will" >
</ context:component-scan >
在 Spring mvc.dispatcher.xml增加:
[html] view plaincopy
< context:component-scan base-package = "com.will" >
< context:exclude-filter type = "annotation" expression = "org.springframework.stereotype.Service" />
</ context:component-scan >
经过如上配置,可以发现事务控制部分的日志如下:
[html] view plaincopy
2013-09-25 09:53:13,031 [http-8080-2] DEBUG [org.springframework.transaction.annotation.AnnotationTransactionAttributeSource] - Adding transactional method 'save' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2013-09-25 09:53:13,037 [http-8080-2] DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'txManager'
2013-09-25 09:53:13,050 [http-8080-2] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Creating new transaction with name [com.will.service.impl.PersonServiceImpl.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2013-09-25 09:53:13,313 [http-8080-2] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Acquired Connection [jdbc:mysql://localhost:3306/mvc?useUnicode = true & characterEncoding = UTF -8, UserName = root @localhost, MySQL-AB JDBC Driver] for JDBC transaction
2013-09-25 09:53:13,323 [http-8080-2] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Switching JDBC Connection [jdbc:mysql://localhost:3306/mvc?useUnicode = true & characterEncoding = UTF -8, UserName = root @localhost, MySQL-AB JDBC Driver] to manual commit
2013-09-25 09:53:13,327 [http-8080-2] DEBUG [org.springframework.jdbc.core.JdbcTemplate] - Executing prepared SQL update
2013-09-25 09:53:13,328 [http-8080-2] DEBUG [org.springframework.jdbc.core.JdbcTemplate] - Executing prepared SQL statement [delete from person where id =?]
2013-09-25 09:53:13,348 [http-8080-2] DEBUG [org.springframework.jdbc.core.JdbcTemplate] - SQL update affected 1 rows
2013-09-25 09:53:13,363 [http-8080-2] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Initiating transaction rollback
2013-09-25 09:53:13,364 [http-8080-2] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Rolling back JDBC transaction on Connection [jdbc:mysql://localhost:3306/mvc?useUnicode = true & characterEncoding = UTF -8, UserName = root @localhost, MySQL-AB JDBC Driver]
2013-09-25 09:53:13,377 [http-8080-2] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Releasing JDBC Connection [jdbc:mysql://localhost:3306/mvc?useUnicode = true & characterEncoding = UTF -8, UserName = root @localhost, MySQL-AB JDBC Driver] after transaction
2013-09-25 09:53:13,378 [http-8080-2] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Returning JDBC Connection to DataSource
在2013-09-25 09:53:13,363处进行了rollback。
运维网声明
1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网 享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com