Spring事务管理使用
发现问题
最近,碰到一个问题,再用spring实现事务管理的时候,发现不起作用,在出异常时,并不会回滚数据库操作。
我想实现的功能如下:
@Transactional(isolation=Isolation.DEFAULT,readOnly=false,propagation=Propagation.REQUIRED,rollbackFor=Exception.class)
public boolean someService() {
mapper.insert();
mapper.insert();
}
TransactionManager的配置如下:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
但是在测试中,在service中手动抛出异常后,第一条insert语句并不会回滚。
之后研究了很久,在控制台打印的消息显示,并没有开启事务。那么我分析应该有下面几种可能:
- 配置错误
- JDBC的AutoCommit没有设置为false
- 控制台信息显示,在Service中,insertA在jdbt连接池中取出了一个连接,插入完后,便将连接返回给了连接池,所以在service中,有多个数据库连接分别处理不同的insert语句。这也可能导致事务失败。
下面来逐步排除:
AutoCommit=true,这个是有可能的,但是通过查看Spring的源码,发现Spring在事务中,是会检测当前连接的AutoCommit选项并把它设置为False,所以排除
最后,通过查看Spring关于Transaction的文档,发现上面说了,如果使用的是DataSourceTransactionManager,那么只能在一个数据库连接上开启事务。那么这么说,应该是数据库连接池的问题了?或者是Spring自己并没有开启事务管理,而是将事务管理委托给了Mysql去实现?这个是有可能的,所以后面再看。
解决问题
然后,我选择使用了切面Aop来实现Spring的事务管理。步骤如下:
//注入transactionManager
@Autowired() @Qualifier("transactionManager1")
private PlatformTransactionManager transactionManager;
这一步是获得自动注入的 transactionManager实例,之后使用TransactionTemplate
//编程式开启事务
TransactionTemplate template = new TransactionTemplate(transactionManager);
是不是很像JDBCTemplate?那么一样的使用内部类实现回调:
//在这边也可以取消返回值,设为void
boolean result = (Boolean) template.execute(new TransactionCallback<Object>() {
public Object doInTransaction(TransactionStatus transactionStatus) {
try {
mapper.insertA();
throw new SQLException();
mapper.insertB();
} catch (Exception e) {mapper.insertB();
//出异常时,手动设置回滚
transactionStatus.setRollbackOnly();
e.printStackTrace();
return false;
}
return true;
}
});
这样,就可以使用Aop手动开启事务了。
经过测试,在两个插入之间手动抛出了异常,insertA的插入被回滚了。从控制台输出信息来看,insertA插入成功后,即把jdbc返回到连接池了,并且事务管理配置的依然是DataSourceTransactionManager,说明前面的数据库连接池的问题被排除了。
分析原因
那么就剩下配置错误了。
实验多次以后,我发现如下配置是可以让声明式事务管理起作用的:
Spring的配置中,取消注入Controller
<context:component-scan base-package="com.test">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
SpringMVC的配置,取消注入Service
<context:component-scan base-package="com.test">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>
配置事务的Service实现某个接口
@Service
public class Test() {
@Transactional(isolation=Isolation.DEFAULT,readOnly=false,propagation=Propagation.REQUIRED,rollbackFor=Exception.class)
public boolean someService() {
mapper.insert();
mapper.insert();
}
}
这样便可以开启事务,并在遇到异常时回滚了。那为什么原来的配置就不行呢?
根本原因是因为spring的context是父子容器,由ServletContextListener 加载spring配置文件产生的是父容器,springMVC加载配置文件产生的是子容器,子容器对Controller进行扫描装配时装配了@Service注解的实例 (@Controller 实例依赖@Service实例),而该实例理应由父容器进行初始化以保证事务的增强处理,所以此时得到的将是原样的Service,没有经过事务加强处理,故而没有事务处理能力
所以在spring的配置中我们要手动exclude controller的注入,不扫描带有@Controller注解的类。因为这些类已经随容器启动时,在servlet-context中扫描过一遍了
在springMVC的配置中扫描业务组件,让springMVC不扫描带有@Service注解的类(留在spring中扫描@Service注解的类),防止事务失效。
在需要配置事务管理的Service类中,需要让类继承一个或几个接口,是因为如果不继承接口,那么会使用cglib动态代理去实现,那么事务管理也会失效。如果实现了接口,那么便会使用jdk自带的动态代理去实现,这样便可以成功的开启事务了。
Spring事务管理使用的更多相关文章
- 【Java EE 学习 52】【Spring学习第四天】【Spring与JDBC】【JdbcTemplate创建的三种方式】【Spring事务管理】【事务中使用dbutils则回滚失败!!!??】
一.JDBC编程特点 静态代码+动态变量=JDBC编程. 静态代码:比如所有的数据库连接池 都实现了DataSource接口,都实现了Connection接口. 动态变量:用户名.密码.连接的数据库. ...
- spring事务管理器设计思想(二)
上文见<spring事务管理器设计思想(一)> 对于第二个问题,涉及到事务的传播级别,定义如下: PROPAGATION_REQUIRED-- 如果当前没有事务,就新建一个事务.这是最常见 ...
- spring事务管理器设计思想(一)
在最近做的一个项目里面,涉及到多数据源的操作,比较特殊的是,这多个数据库的表结构完全相同,由于我们使用的ibatis框架作为持久化层,为了防止每一个数据源都配置一套规则,所以重新实现了数据源,根据线程 ...
- 事务管理(下) 配置spring事务管理的几种方式(声明式事务)
配置spring事务管理的几种方式(声明式事务) 概要: Spring对编程式事务的支持与EJB有很大的区别.不像EJB和Java事务API(Java Transaction API, JTA)耦合在 ...
- Spring事务管理器的应对
Spring抽象的DAO体系兼容多种数据访问技术,它们各有特色,各有千秋.像Hibernate是非常优秀的ORM实现方案,但对底层SQL的控制不太方便:而iBatis则通过模板化技术让你方便地控制SQ ...
- Spring事务管理(转)
1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必须是 ...
- [Spring框架]Spring 事务管理基础入门总结.
前言:在之前的博客中已经说过了数据库的事务, 不过那里面更多的是说明事务的一些锁机制, 今天来说一下Spring管理事务的一些基础知识. 之前的文章: [数据库事务与锁]详解一: 彻底理解数据库事务一 ...
- Spring 事务管理 01 ——
目录: 参考: 1.Spring 事务管理高级应用难点剖析: 第 1 部分
- Spring 事务管理原理探究
此处先粘贴出Spring事务需要的配置内容: 1.Spring事务管理器的配置文件: 2.一个普通的JPA框架(此处是mybatis)的配置文件: <bean id="sqlSessi ...
- Spring 事务管理高级应用难点剖析--转
第 1 部分 http://www.ibm.com/search/csass/search/?q=%E4%BA%8B%E5%8A%A1&sn=dw&lang=zh&cc=CN& ...
随机推荐
- javascript基础学习(十四)
javascript之表单对象 学习要点: 表单对象 文本框 按钮 单选框和复选框 一.表单对象 在HTML文档中可能会出现多个表单,也就是说,一个HTML文档中可能出现多个<form>标 ...
- 你好,C++(12)如何管理多个类型相同性质相同的数据?3.6 数组
3.6 数组 学过前面的基本数据类型之后,我们现在可以定义单个变量来表示单个的数据.例如,我们可以用int类型定义变量来表示公交车的216路:可以用float类型定义变量来表示西红柿3.5元一斤.但 ...
- 【USACO 2.4.1】两只塔姆沃斯牛
[题目描述] 两只牛逃跑到了森林里.农夫John开始用他的专家技术追捕这两头牛.你的任务是模拟他们的行为(牛和John). 追击在10x10的平面网格内进行.一个格子可以是: 一个障碍物, 两头牛(它 ...
- Python datetime time 常用操作
测试版本: Python 2.7 获取当前时间的两种方法 import datetime,time now = time.strftime("%Y-%m-%d %H:%M:%S") ...
- 在jQuery.getData中renderCallback使用不同创建方式的结果
JavaScript 中需要创建函数的话,有两种方法:函数声明.函数表达式,各自写法如下:// 方法一:函数声明function foo() {}// 方法二:函数表达式var foo = funct ...
- thinkphp G方法的华丽升级
ThinkPHP长期以来需要通过debug_start.debug_end方法甚至Debug类才能完成的功能,3.1版本中被一个简单的G方法取代了,不可不谓是一次华丽升级. G方法的作用包括标记位置和 ...
- delphi 创建数据库配置文件(TIniFile)
一.有必要了解INI文件的结构: ;注释 [小节名] 关键字=值 ... ---- INI文件允许有多个小节,每个小节又允许有多个关键字, “=”后面是该关键字的值. ---- 值的类型有三种:字符串 ...
- iOS 写入文件保存数据的方式
在iOS开发过程中,不管是做什么应用,都会碰到数据保存的问题.将数据保存到本地,能够让程序的运行更加流畅,不会出现让人厌恶的菊花形状,使得用户体验更好.下面介绍一下数据保存的方式: 1.NSKeye ...
- 一分钟让你明白CSS中的盒模型
想必初学者对CSS盒模型总是很困惑吧.下面一分钟让你彻底明白盒模型: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" &q ...
- java线程同步问题
Java面试当中,线程可以说是必考内容,在看面试题的时候发现一遍很全的讲解Java面试题的博客:http://blog.csdn.net/csh624366188/article/details/80 ...