ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【踩坑日记】那些年Spring声明式事务不回滚的离奇事件

2020-06-16 19:38:04  阅读:231  来源: 互联网

标签:事务管理 事务 RuntimeException Spring 回滚 方法 离奇 不回 异常


最近在做一个项目的时候,写着写着到最后自测的时候发现存在事务不回滚的情况,检查数据库时还是有发现数据不一致的情况,当时我手里的西瓜刀就不冷静了,明明大家都是用的注解@Transactional,凭什么我的腰间盘就这么突出???
后面想想肯定是事务没起作用,出现异常的时候事务没有回滚。在项目中配置的时候我采用的是声明式事务,个人觉得优点:使用方便,一次配置就可以了;缺点:事务的粒度比较大,只能到方法级别

在我的不懈…嗯?百度之下,后面找到事务不回滚的原因有以下两点:
一.try…catch异常
Spring的事务管理默认只对出现运行期异常(java.lang.RuntimeException及其子类)进行回滚,如果一个方法抛出Exception或者Checked异常,Spring事务管理默认不进行回滚!
贫僧的坑就在这个地方,使用了try…catch子句捕获异常并throw了一个自定义异常,原来是因为我自定义的异常不是 RuntimeException,这种情况导致了事务未回滚,真的是大意出Bug,老脸一红。话不多说,上代码:

@Transactional(propagation = Propagation.MANDATORY)
public void updateXianYuInfo(People people) throws TransactionException{
	try{
	  peopleDao.updateByPrimaryKey(people);
	  peopleLogDao.updateByPrimaryKey(people);
	}catch(Exception e){
		Logger.error(e.getMessage());
		throw new TransactionException(e.getErrCode(),e.getMessage());
	}
}

TransactionException自定义异常如下:

public class TransactionExceptionextends extends Exception {
  // 自定义异常
}

上面代码中的声明式事务在出现异常的时候,事务是不会回滚的。在代码中我虽然捕获了异常,但是同时我也抛出了异常,为什么事务未回滚呢?猜测是异常类型不对,于是苦苦查询原因,找到了答案:

在默认配置中,Spring FrameWork 的事务框架代码只会将出现runtime, unchecked 异常的事务标记为回滚;也就是说事务中抛出的异常时RuntimeException或者是其子类,这样事务才会回滚(默认情况下Error也会导致事务回滚)。在默认配置的情况下,所有的 checked 异常都不会引起事务回滚。

Note:Unchecked Exception包括Error与RuntimeException.
RuntimeException的所有子类也都属于此类。另一类就是checked Exception。

二.Service类内部方法调用

大概就是 Service 中有一个方法 A,会内部调用方法 B, 方法 A 没有事务管理,方法 B 采用了声明式事务,通过在方法上声明 Transactional 的注解来做事务管理。
但是…声明式事务是通过AOP动态代理实现的,这样会产生一个代理类来做事务管理,而目标类(service)本身是不能感知代理类的存在的。
最后总结,在方法 A 中调用方法 B,实际上是通过“this”的引用,也就是直接调用了目标类的方法,而非通过 Spring 上下文获得的代理类,所以事务是不会开启的。

那么问题来了,挖掘机学校哪家强…嗯?搞错了,重来,大家所关心的事务不回滚的解决方案有哪些呢

a. 如果是service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw new RuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层要继续捕获这个异常并处理

b. 在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常(现在我的项目的做法)

c.在注解@Transactional中添加 rollbackFor={TransactionException.class}

这是一个本猿真实的挖坑以及埋坑的经历,希望能帮到在坐的各位老铁,挥一挥衣袖,深藏功与名~~~

标签:事务管理,事务,RuntimeException,Spring,回滚,方法,离奇,不回,异常
来源: https://blog.csdn.net/weixin_42777004/article/details/106765215

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有