springJdbc(jdbcTemplate)事物拦截失效问题解决先贴上l和l代码:
1<context-param>
2<param-name>contextConfigLocation</param-name>
3<param-value>
4                  classpath:l,
5                  classpath:l
6</param-value>
7</context-param>
8
9<listener>
10<description>spring</description>
11<listener-class>org.t.ContextLoaderListener</listener-class>
12</listener>
13
14<servlet>
15<servlet-name>SpringMvc</servlet-name>
16<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
17<init-param>
18<param-name>contextConfigLocation</param-name>
19<param-value>
20                  classpath:l
21</param-value>
22</init-param>
23<load-on-startup>1</load-on-startup>
24</servlet>
25<servlet-mapping>
26<servlet-name>SpringMvc</servlet-name>
27<url-pattern>/</url-pattern>
28</servlet-mapping>
29<servlet>
1<?xml version="1.0" encoding="UTF-8"?>
2<beans
3xmlns="/schema/beans"
4      xmlns:xsi="/2001/XMLSchema-instance"
5      xmlns:tx="/schema/tx"
6      xmlns:aop="/schema/aop"
7      xmlns:context="/schema/context"
8  xsi:schemaLocation="
9  /schema/beans
10  /schema/beans/spring-beans-4.2.xsd
11  /schema/tx
12  /schema/tx/spring-tx-4.2.xsd
13  /schema/aop
14  /schema/aop/spring-aop-4.2.xsd
15  /schema/context
16  /schema/context/spring-context-4.2.xsd"    default-autowire="byName">
17
18<!-- 引⼊属性⽂件 -->
19<bean id="propertyConfigurer" class="org.springframework.fig.PropertyPlaceholderConfigurer">
20<property name="locations">
21<list>
22<value>classpath:config/jdbc.properties</value>
23<value>classpath:config/redis.properties</value>
24<value>classpath:config/contract-mail.properties</value>
25</list>
27</bean>
28
29<!-- 加载config.properties,为了使该注解⽣效:@Value("#{config['email.ail']}") -->
30<bean id="config" class="org.springframework.fig.PropertiesFactoryBean">
31<!-- false表⽰当没到这个配置⽂件时,应⽤程序应该报错        -->
32<property name="ignoreResourceNotFound" value="false"/>
33<property name="locations">
34<list>
35<value>classpath:config/config.properties</value>
36</list>
37</property>
38</bean>
39
40<!-- 配置数据源 -->
41<bean name="dataSourceSpied" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> 42<property name="url" value="${jdbc_url}"/>
43<property name="username" value="${jdbc_username}"/>
44<property name="password" value="${jdbc_password}"/>
45<property name="initialSize" value="${jdbc_initialSize}"/>
46<property name="maxActive" value="${jdbc_maxActive}"/>
47<property name="minIdle" value="${jdbc_minIdle}"/>
48<property name="maxWait" value="${jdbc_maxWait}"/>
49<property name="validationQuery" value="${validationQuery}"/>
50<property name="testOnBorrow" value="false"/>
51<property name="testOnReturn" value="false"/>
52<property name="testWhileIdle" value="true"/>
53<!-- 配置间隔多久才进⾏⼀次检测,检测需要关闭的空闲连接,单位是毫秒 -->
54<property name="timeBetweenEvictionRunsMillis" value="60000"/>
55<!-- 打开removeAbandoned功能 -->
56<property name="removeAbandoned" value="true"/>
57<!-- 1800秒,也就是30分钟 -->
58<property name="removeAbandonedTimeout" value="180"/>
59<!-- 关闭abanded连接时输出错误⽇志 -->
60<property name="logAbandoned" value="true"/>
61<!-- 监控数据库 -->
62<property name="filters" value="mergeStat"/>
63</bean>
64
65<bean id="dataSource" class="net.sf.log4jdbc.Log4jdbcProxyDataSource">
66<constructor-arg ref="dataSourceSpied"/>
67</bean>
68
69<!-- myBatis⽂件 -->
70<bean id="sqlSessionFactory" class="batis.spring.SqlSessionFactoryBean">
71<property name="dataSource" ref="dataSource"/>
72<property name="mapperLocations" value="classpath*:mapper/*.xml"/>
73<property name="plugins">
74<list>
75<!-- 物理分页 -->
76<bean class="com.batis.paginator.OffsetLimitInterceptor">
77<property name="dialectClass"  value="com.batis.paginator.dialect.OracleDialect"></property> 78</bean>
79</list>
80</property>
jdbctemplate insert81</bean>
82
83<!-- 配置事务管理器 -->
84<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
85<property name="dataSource" ref="dataSourceSpied"/>
86</bean>
87<!-- 声明式事务管理,拦截多个包下⾯事物      and execution(* service.*Service.*(..))  -->
88<aop:config>
89<aop:advisor pointcut="execution(* service.*Service.*(..))"
90                advice-ref="myAdvice"/>
92<tx:advice id="myAdvice" transaction-manager="transactionManager">
93<tx:attributes>
94<tx:method name="addCommandExec" propagation="REQUIRES_NEW"/><!-- 这个名字的service⽅法使⽤新事物,不使⽤继承事物 -->
95<tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.RuntimeException"/>
96<!-- <tx:method name="*" read-only="true"/> -->
97<!-- <tx:method name="*" read-only="true" rollback-for="com.smvc.util.DaoException"/> -->
98</tx:attributes>
99</tx:advice>
100
101<!-- ⾃动扫描组件,多个包⽤逗号隔开,需要把controller去掉,否则影响事务管理 -->
102<context:component-scan base-package=",and">
104<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
105</context:component-scan>
106
107<bean id="jdbcTemplate" class="org.JdbcTemplate">
108<property name = "dataSource" ref="dataSource"/>
109</bean>
110
111<bean id="namedJdbcTemplate" class="org.amedparam.NamedParameterJdbcTemplate">
112<constructor-arg ref="dataSource"/>
113</bean>
114
115</beans>
bug问题表现:
在Service⽅法中,事物不起作⽤,bug表现如下:
1) 期望:Service⽅法中save()⽅法执⾏前开启事物,执⾏后提交事物,提交事物后才可以在数据库⾥看到那条新insert的数据。
2) 现象:事物不起作⽤,在save()⽅法未结束时,数据库中已经可以看到那条新insert的数据。save()⾥使⽤的是jdbcTemplate对象执⾏的SQL。
问题解决思路:
由于是springMVC项⽬,为了更快的debug,省去tomcat启动时间,建⽴了Junit测试类模拟spring容器启动,代码贴上如下:
service;
2import org.apache.log4j.Logger;
3import org.junit.Test;
4import org.junit.runner.RunWith;
5import org.springframework.beans.factory.annotation.Autowired;
6import st.context.ContextConfiguration;
7import st.context.junit4.SpringJUnit4ClassRunner;
8import st.context.web.WebAppConfiguration;
9
11 @WebAppConfiguration
12 @RunWith(SpringJUnit4ClassRunner.class)
13 @ContextConfiguration({ "classpath:l"
14    ,"classpath:l","classpath:l"})
15public class SystemUserServiceTest {
16private final static Logger logger= Logger(SystemUserServiceTest.class);
17
18    @Autowired
19private SystemUserService systemUserService;
20    @Test
21public void test() {
22int result2 = systemUserService.insertSystemUser();
23        logger.info("result2 == " + result2);
24    }
25
26 }
第⼀次解决⽅法:百度了很多资料,都说l和l的注解扫描器要注意互相排除,也就是controller层的要排除扫描service类,service层的要排除controller层,我仔细对⽐了两个xml配置⽂件,与⽹上写的解决⽅法⼀致。所以不是这个原因出现的问题。
第⼆次解决⽅法:我的l配置⽂件⾥⾯,使⽤的是transactionManager对象来做事物管理类,所以跟踪spring事物类org.springframework.jdbc.datasource.DataSourceTransactionManager,看看到底有没有进⼊事物管理。分别在DataSourceTransactionManager类⾥的doBegin事物开启和doCommit事物提交⽅法⾥打上断点,debug开始跟踪。debug过程中发现,spring容器确实在save()⽅法之前执⾏的doBegin()事物开启,确实在save()执⾏完毕之后执⾏的doCommit()事物提交。可是当save()⽅法还未彻底结束之前,也就是doCommit()⽅法也尚未执⾏之前,数据库就有这条新insert记录了!所以不是事物配置没有起作⽤的原因。
第三次解决⽅法:这次换个思路,我在save()⽅法中执⾏sql语句的代码是:jdbcTemplate.update(insertSql);  我在这个update⽅法⾥打了断点,⼀直跟踪下去,终于发现了bug原因!
bug原因:
jdbcTemplate.update(insertSql)  中的update⽅法⾥的dataSource对象在debug过程中看到此对象ID是111,⽽在之前DataSourceTransactionManager类⾥⾯的dataSource对象在debug过程中此对象ID是81,说明jdbcTemplate对象拿到的dataSource 对象和事物管理器⾥⾯的dataSource对象根本就不是同⼀个!
bug修正:
把l⾥的实际sql 执⾏对象所引⽤的dataSource换成和事物管理器的dataSource同⼀个对象就好了。
1<bean id="jdbcTemplate" class="org.JdbcTemplate">
2<property name = "dataSource" ref="dataSourceSpied"/>
3</bean>
4
5<bean id="namedJdbcTemplate" class="org.amedparam.NamedParameterJdbcTemplate">
6<constructor-arg ref="dataSourceSpied"/>
7</bean>