springJdbc(jdbcTemplate)事物拦截失效问题解决
先贴上web.xml和spring-jdbc.xml代码:
web.xml代码:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:config/spring-jdbc.xml,
classpath:config/spring-redis.xml
</param-value>
</context-param> <listener>
<description>spring监听器</description>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> <servlet>
<servlet-name>SpringMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:config/spring-mvc.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>
spring-jdbc.xml代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd" default-autowire="byName" > <!-- 引入属性文件 -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config/jdbc.properties</value>
<value>classpath:config/redis.properties</value>
<value>classpath:config/contract-mail.properties</value>
</list>
</property>
</bean> <!-- 加载config.properties,为了使该注解生效:@Value("#{config['email.alarm.sender.email']}") -->
<bean id="config" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<!-- false表示当没找到这个配置文件时,应用程序应该报错 -->
<property name="ignoreResourceNotFound" value="false" />
<property name="locations">
<list>
<value>classpath:config/config.properties</value>
</list>
</property>
</bean> <!-- 配置数据源 -->
<bean name="dataSourceSpied" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc_url}" />
<property name="username" value="${jdbc_username}" />
<property name="password" value="${jdbc_password}" />
<property name="initialSize" value="${jdbc_initialSize}" />
<property name="maxActive" value="${jdbc_maxActive}" />
<property name="minIdle" value="${jdbc_minIdle}" />
<property name="maxWait" value="${jdbc_maxWait}" />
<property name="validationQuery" value="${validationQuery}" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="true" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="180" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="true" />
<!-- 监控数据库 -->
<property name="filters" value="mergeStat" />
</bean> <bean id="dataSource" class="net.sf.log4jdbc.Log4jdbcProxyDataSource">
<constructor-arg ref="dataSourceSpied"/>
</bean> <!-- myBatis文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath*:mapper/*.xml" />
<property name="plugins">
<list>
<!-- 物理分页 -->
<bean class="com.github.miemiedev.mybatis.paginator.OffsetLimitInterceptor">
<property name="dialectClass" value="com.github.miemiedev.mybatis.paginator.dialect.OracleDialect"></property>
</bean>
</list>
</property>
</bean> <!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceSpied" />
</bean>
<!-- 声明式事务管理,拦截多个包下面事物 and execution(* com.xxx.service.*Service.*(..)) -->
<aop:config>
<aop:advisor pointcut="execution(* com.xxx.service.*Service.*(..))"
advice-ref="myAdvice"/>
</aop:config>
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="addCommandExec" propagation="REQUIRES_NEW"/> <!-- 这个名字的service方法使用新事物,不使用继承事物 -->
<tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.RuntimeException" />
<!-- <tx:method name="*" read-only="true"/> -->
<!-- <tx:method name="*" read-only="true" rollback-for="com.smvc.util.DaoException"/> -->
</tx:attributes>
</tx:advice> <!-- 自动扫描组件,多个包用逗号隔开,需要把controller去掉,否则影响事务管理 -->
<context:component-scan base-package="com.xxx,com.xxx.command">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name = "dataSource" ref="dataSource" />
</bean> <bean id="namedJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="dataSource" />
</bean> </beans>
bug问题表现:
在Service方法中,事物不起作用,bug表现如下:
1) 期望:Service方法中save()方法执行前开启事物,执行后提交事物,提交事物后才可以在数据库里看到那条新insert的数据。
2) 现象:事物不起作用,在save()方法未结束时,数据库中已经可以看到那条新insert的数据。save()里使用的是jdbcTemplate对象执行的SQL。
问题解决思路:
由于是springMVC项目,为了更快的debug,省去tomcat启动时间,建立了Junit测试类模拟spring容器启动,代码贴上如下:
package com.xxx.service;
import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration; @WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:config/spring-mybatis.xml"
,"classpath:config/spring-redis.xml","classpath:config/spring-mvc.xml"})
public class SystemUserServiceTest {
private final static Logger logger= Logger.getLogger(SystemUserServiceTest.class); @Autowired
private SystemUserService systemUserService;
@Test
public void test() {
int result2 = systemUserService.insertSystemUser();
logger.info("result2 == " + result2);
} }
第一次解决方法:百度了很多资料,都说spring-mvc.xml和spring-jdbc.xml的注解扫描器要注意互相排除,也就是controller层的要排除扫描service类,service层的要排除controller层,我仔细对比了两个xml配置文件,与网上写的解决方法一致。所以不是这个原因出现的问题。
第二次解决方法:我的spring-jdbc.xml配置文件里面,使用的是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修正:
把spring-jdbc.xml里的实际sql 执行对象所引用的dataSource换成和事物管理器的dataSource同一个对象就好了。
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name = "dataSource" ref="dataSourceSpied" />
</bean> <bean id="namedJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="dataSourceSpied" />
</bean>
springJdbc(jdbcTemplate)事物拦截失效问题解决的更多相关文章
- 访问前台页面${pageContext.request.contextPath}/el表达式失效问题解决
访问前台页面${pageContext.request.contextPath}/el表达式失效问题解决 2017年05月09日 10:54:18 AinUser 阅读数:922 标签: el表达式4 ...
- pycharm 2017 序列号失效问题解决(2016-2017版本都有效)
pycharm 序列号失效问题解决 this license BIG3CLIK6F has been cancelled 具体如下: 对,没错,这个激活码本来可以使用到2018年的,但是,忽然间 ...
- sublime text的Ctrl+alt+up快捷键失效问题解决
上周一入职了新公司,安装了sublime text3 之后发现多行光标定位快捷键"Ctrl+alt+up|down"不能使用了.最后发现是快捷键冲突.我的电脑安装的是win7专业版 ...
- IE下IFrame引用跨域站点页面时,Session失效问题解决
问题场景:在一个应用(集团门户)的某个page中, 通过IFrame的方式嵌入另一个应用(集团实时监管系统)的某个页面. 当两个应用的domain 不一样时, 在被嵌入的页面中Session失效.(s ...
- .gitignore失效问题解决
.gitignore失效背景: 本地Mac上使用Unity新建了一个项目,使用git init将项目初始化为仓库,此时commit.随后,加入.gitignore文件,再次commit.然后提交整个仓 ...
- [异常解决] ubuntu上安采用sudo启动的firefox,ibus输入法失效问题解决
采用sudo启动的应用是root权限的应用, ibus失效是因为ibus的初始配置采用user权限: 而root下运行的firefox输入法的配置还是停留在默认情况~ 解决方案是在shell下以roo ...
- IE11里边form拦截失效,永远被弹回登录页
现象描述: 1.在某些服务器上发布了程序以后,用IE11去浏览程序(试了多台电脑都一样),发现总是登录不进去,因为登录之后总是被立即反弹回登录页面,就像是登录后写入的票据瞬间丢失一样. 2.但是同一套 ...
- IE6、7 a链接内图片加滤镜后导致a标签链接失效问题解决
今天在项目中遇到一个ie6.7浏览器下a链接失效的问题,查询大量资料,最终找到完美的解决方案,如下: 解决方法: 为a标签加样式{*background:url(#);*zoom:1;} 为img外部 ...
- reload(sys)后print失效问题解决
python版本: python2.7.6 #查看python默认编码格式 >>> import sys >>> print sys.getdefaultencod ...
随机推荐
- mysql安装和启动
1.在cmd的bin目录执行 mysqld --initialize-insecure程序会在动MySQL文件夹下创建data文件夹以及对应的文件2.bin目录下执行,mysqld --install ...
- Java数组声明、初始化
维数组的声明方式:type var[]; 或type[] var; 声明数组时不能指定其长度(数组中元素的个数), Java中使用关键字new创建数组对象,格式为:数组名 = new 数组元素的类型 ...
- C语言:统计数字空格其他字符程序
#include <stdio.h> int main(){ char t; int num=0; int spac=0; int other=0; int sum=0; printf(& ...
- 第一个java程序中文乱码以及如何解决
出现问题:编码gbk的不可映射字段 原因:.java文件的编码与cmd命令执行器使用的编码不一致 我们使用的.java文件的编码为UTF-8 Cmd默认使用的编码为GBK: 解决方式统一编码: 方法1 ...
- cut语法2
linux每日一命令--cut--按文件大小排序 显示前100行 显示后五列 ll -Sh|head -n 100|cut -d ' ' -f 5- 一.基本语法cut是一个选取命令,以行为单位,用指 ...
- 解决启动vs2010 未能找到自动配置的设置文件
今天室友把固态拆掉,重新安上.打开vs2010出现 打开项目,出现 找了许多方法都无效. 发现c:user\Administer\documents\下,vs2010 .vs webset 那些文件点 ...
- 01_Mybaits逆向工程maven版
1.创建generatorSqlmapCustom工程 2.修改pom文件 <?xml version="1.0" encoding="UTF-8"?&g ...
- cocos2dx创建win32项目一般步奏
1.导入一个新项目步奏:解决方案:右键->添加->添加现有项目->添加依赖项目libCocoStudioD:\work\CannonDefender\cocos2d\cocos\ed ...
- Gym101889B. Buggy ICPC(打表)
比赛链接:传送门 题目: Problem B – Buggy ICPC Author : Gabriel Poesia, Brasil Alan Curing is a famous sports p ...
- day06 内存地址 小数据池缓存机制
1. 内存相关 示例一 v1=[11,22,33] v2=[11,22,33] #值相等 内存地址不等 v1=11 v2=11 #按理说内存地址应该不等,但是python为了优化使其内存地址相等 v1 ...