Spring事务管理回滚问题
Spring事务管理不能回滚问题
在前段时间学习SpringMVC的练习中,碰到声明式事务管理时,事务不能回滚的情况,通过查看博客和资料,解决了问题。
原因
导致Spring事务管理不能回滚的原因有两个:一是Service内部方法调用,二是使用了try...catch异常。
Service内部方法调用
现在我的Service层中,定义一个转账的功能给它加上事务,而另一个方法直接调用并没有事务。
@Service
public class YHService{
// 开启事务
@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
public void transferDemo1(){
// 转账逻辑代码。。。
int i = 1/0;
}
// 未开启事务
public void transferDemo2(){
transferDemo1();
}
}
现在编写Test
public class YHServiceTest{
@Autowired
private YHService service;
@Test
public void testDemo1(){
service.transferDemo1();
}
@Test
public void testDemo2(){
service.transferDemo2();
}
}
结果就是调用testDemo1时,事务发生了回滚,而调用testDemo2时事务并没有回滚,这是为什么?
原来使用声明式事务来进行管理时,是通过AOP动态产生代理类(serviceProxy)来进行事务管理,而目标类(service)是没有事务管理的,所以在service内部(this)调用的方法是不能被serviceProxy事务管理所负责,可能会好奇我的testDemo2不就是通过serviceProxy调用的吗?为什么transferDemo2能进行事务管理而transferDemo1却不能?看看下面serviceProxy事务管理运行的原理把。

看完之后就清楚了,我们使用Spring的事务管理,首先是调用serviceProxy,再调用service的目标方法退出方法时提交/回滚。当我们调用transferDemo2时,此时的方法加入了serviceProxy的事务管理,而transferDemo2内通过了this调用了transferDemo1而此时尽管用注解/xml的形式声明了事务管理,但是却是通过service来调用该方法的,并不是serviceProxy调用,所以他保持的是和transferDemo2一样的事务,此处即为没有事务。
简而言之就是:目标对象内部的自我调用将无法实施切面中的增强,如果要实现,就只能通过代理类去调用该目标方法即可达到目的。代码变现就是将this调用换成serviceProxy调用就可以了,可以用注入方式达成目的,很多种方法,可以自行查资料。
try...catch...
在刚刚开始学习Spring事务的时候我们并没有去给逻辑代码加上try...catch..直接让程序异常回滚,但是也不能一直这样,有些情况下我们需要处理异常就要用try...catch...去处理异常,所以我们接下来看看再try...catch...中程序异常,事务是否能回滚
mapper层:
public interface DaoMapper {
// 转出
@Update("update t_user set balance=balance-#{money} where id=#{id}")
void push(@Param("id") int id, @Param("money") double money);
// 转入
@Update("update t_user set balance=balance+#{money} where id=#{id}")
void pull(@Param("id")int id, @Param("money")double money);
}
Service:
@Service
public class UserServerImpl implements UserServer {
private DaoMapper mapper;
@Autowired
public void setMapper(DaoMapper mapper) {
this.mapper = mapper;
}
@Override
public void transferAccounts(int pushId, double money, int pullId) {
try {
mapper.push(pushId, money);
int i = 7 / 0;
mapper.pull(pullId, money);
}catch (Exception e){
System.out.println("程序异常,事务回滚");
}
}
}
上面的代码我们对其中的异常进行了捕获并处理,运行发现事务并没有进行回滚,这是为什么,猜测应该是跟try...catch...有关,查阅资料博客,发现我们如果对异常进行了手动捕获处理,并没有throw出异常这样导致了Spring的事务管理拦截不到异常,就不会对事务进行回滚,OK那么我们加上throw e;运行程序,结果正常,事务也回滚了。
奇怪的是我抛出的是Exception类型的异常,也没有在xml中的事务管理进行rollback-for配置,为啥会回滚呢?
在默认配置中,Spring FrameWork 的事务框架代码只会将出现runtime, unchecked 异常的事务标记为回滚;也就是说事务中抛出的异常时RuntimeException或者是其子类,这样事务才会回滚(默认情况下Error也会导致事务回滚)。在默认配置的情况下,所有的 checked 异常都不会引起事务回滚。
按理来说Spring不应该回滚,后面我将改成了throw new Exception(),运行程序发现事务没有回滚,改成throw new RuntimeException(),运行程序发现事务回滚了。
好像和throw的对象有关,之前我们throw出的是我们当前捕获的异常对象,发现被Spring事务管理回滚了,后面我们throw出的是新的Exception实例对象,没有被Spring事务管理拿到,而throw出的是新的RuntimeException实例对象却被Spring事务管理拿到了,当我在xml文件中配置了rollback-for="Exception",发现throw出新的Exception实例对象也能被捕获到并回滚。我好奇的是符合上诉的异常回滚规则的竟然是throw出新的异常类型实例对象。而不是catch中的对象实例,这是为什么?有没有大神解惑一下,谢谢!
Spring事务管理回滚问题的更多相关文章
- Spring事务管理——回滚(rollback-for)控制
探讨Spring事务控制中,异常触发事务回滚原理.文章进行了6种情况下的Spring事务是否回滚. 以下代码都是基于Spring与Mybatis整合,使用Spring声明式事务配置事务方法. 1.不捕 ...
- Spring事务不回滚原因分析
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离. 在我完成一个项目的时候,遇到了一个Spring事务不回滚的问题,通过aspectJ和@Transacti ...
- Spring事务异常回滚,捕获异常不抛出就不会回滚(转载) 解决了我一年前的问题
最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了....... 为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异常 ...
- springmvc mybatis 声明式事务管理回滚失效,(checked回滚)捕捉异常,传输错误信息
一.知识点及问题 后端框架: Spring .Spring mvc .mybatis 业务需求: client先从服务端获取用户大量信息到client,编辑完毕之后统一Post至服务端,对于数据的改动 ...
- Spring事务异常回滚,捕获异常不抛出就不会回滚
最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了....... 为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异常 ...
- 【转】Spring事务异常回滚,捕获异常不抛出就不会回滚
最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了....... 为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异 ...
- Spring事务异常回滚
最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了....... 为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异常 ...
- spring事务没回滚
最近遇见一个问题,用spring管理实务,在service层处理数据,保存数据时出现异常,但没有回滚,检查了一下,发现是因为我用try catch将异常进行捕获了,没有抛出导致的:默认spring事务 ...
- SpringMVC+Spring 事务无法回滚的问题
问题描述: Controller里面执行Service的方法,Service方法抛出异常,但是没有按照事务配置的方式回滚: Service的事务配置没有问题: 出现此问题的原因: 在springmvc ...
随机推荐
- 论文笔记:(ICCV2019)KPConv: Flexible and Deformable Convolution for Point Clouds
目录 摘要 一.引言 二.相关工作 投影网络 图卷积网络 逐点多层感知器网络 点卷积网络 三.核点卷积 3.1由点定义的核函数 3.2刚性的或可变形的核 3.3核点网络层 3.4核点网络架构 四.实验 ...
- 别再用CSV了,更高效的Python文件存储方案
CSV无可厚非的是一种良好的通用文件存储方式,几乎任何一款工具或者编程语言都能对其进行读写,但是当文件特别大的时候,CSV这种存储方式就会变得十分缓慢且低效.本文将介绍几种在Python中能够代替CS ...
- PaddlePaddle之猫狗大战(本地数据集)
新手入门PaddlePaddle的一个简单Demo--猫狗大战 主要目的在于整体了解PP用卷积做图像分类的流程,以及最最重要的掌握自定义数据集的读取方式 猫狗数据集是从网络上下载到工作目录的. 本项目 ...
- 拦截器HandlerInterceptorAdapter的postHandle和afterCompletion无法获取response返回值问题
缘起 有一个需求,在进入controller之前验证调用次数是否超过限制,在响应之后判断是否正常返回,对调用次数进行+1,发现带@RestController的类和带@ResponseBody的方法在 ...
- CVE-2021-21972 vSphere Client RCE复现,附POC & EXP
漏洞简介 vSphere 是 VMware 推出的虚拟化平台套件,包含 ESXi.vCenter Server 等一系列的软件.其中 vCenter Server 为 ESXi 的控制中心,可从单一控 ...
- STM32—位带操作
STM32中的位带操作: 名字为位带操作,实际上是对位的操作,位操作就是可以单独的对一个比特位读和写,这个在 51 单片机中非常常见. 51 单片机中通过关键字 sbit 来实现位定义, STM32 ...
- xml的约束
一.DTD约束xml 1.约束介绍 由于xml的标签由用户自己定义,因此在开发的时候,每个人都可以根据自己的需求来定义xml标签,这样导致项目中的xml难以维护,因此需要使用一定的规范机制来约束xml ...
- NOIP 模拟 $24\; \rm block$
题解 \(by\;zj\varphi\) 因为它要求大于它的且放在它前的数的个数要小于它的 \(key\) 值,所以先按 \(\rm val\) 值排序,然后按 \(\rm key\) 值排序,按顺序 ...
- 题解 block
传送门 如果不想让next_permutation()自动忽略重复元素,可以在比较函数里加个rk之类的东西使它们不同(next_permutation()不用等于号) 关于第一问:貌似也是一个挺常见的 ...
- 《深入浅出vue.js》阅读笔记之数组变化侦测
1.如何追踪变化 数组的侦测方式和对象不同,比如: this.list.push(1) 此时并不会像改变对象一样触发setter. 同理,要侦测数组的变化意味着我们在改变数组的时候得到通知,如图,我们 ...