@Transactional注解真的有必要声明rollbackFor属性吗?
@Transactional注解真的有必要声明rollbackFor属性吗?
今天在看spring的事务底层源码时,想到一个问题,@Transactional注解真的有必要声明rollbackFor属性吗?因为之前有许多资料,包括公司的java编码规范上也有提及到这一点。
不知道读者们有没想过这个问题,但我看完源码后,个人觉得是没必要的。见解不到位的话,希望读者能指明。
异常:如下图所示,我们都知道Exception分为运行时异常RuntimeException和非运行时异常(检查时异常)。

那么spring默认会对如上的哪些异常进行回滚呢?
答案:RuntimeException、Error.
spring源码如下说明:
spring在执行方法抛出异常后,会调用completeTransactionAfterThrowing方法,也在该方法中会去判断并执行是回滚还是提交操作。
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
// transactionAttribute的实现类为RuleBasedTransactionAttribute,父类为DefaultTransactionAttribute
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
else {
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
我们看到这个if分支进行分析,如果该if满足,则会进行回滚。
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex))
查看txInfo.transactionAttribute.rollbackOn(ex)方法,其中的this.rollbackRules就是我们在@Transactional注解上配置的rollbackFor属性,
public boolean rollbackOn(Throwable ex) {
RollbackRuleAttribute winner = null;
int deepest = Integer.MAX_VALUE;
if (this.rollbackRules != null) {
// 遍历所有的RollbackRuleAttribute,判断现在抛出的异常ex是否匹配RollbackRuleAttribute中指定的异常类型的子类或本身
for (RollbackRuleAttribute rule : this.rollbackRules) {
int depth = rule.getDepth(ex);
if (depth >= 0 && depth < deepest) {
deepest = depth;
winner = rule;
}
}
}
// User superclass behavior (rollback on unchecked) if no rule matches.
if (winner == null) {
return super.rollbackOn(ex);
}
// ex所匹配的RollbackRuleAttribute,可能是NoRollbackRuleAttribute,如果是匹配的NoRollbackRuleAttribute,那就表示现在这个异常ex不用回滚
return !(winner instanceof NoRollbackRuleAttribute);
}
我这里简单配了个ServiceException。如下图

根据一:在rollbackFor属性元素遍历时,会根据getDepth方法去找抛出的异常,是不是就是我们声明的rollbackFor属性中的异常,如果是,判断是不是NoRollbackRuleAttribute类型,是的话就不回滚,否则就回滚。
再看getDepth方法,会根据抛出的异常,判断异常名字是否跟我们声明的异常是否相同,相同则返回,不同则递归抛出异常的父类,直到遍历到Throwable.class顶类。
private int getDepth(Class<?> exceptionClass, int depth) {
if (exceptionClass.getName().contains(this.exceptionName)) {
// Found it!
return depth;
}
// If we've gone as far as we can go and haven't found it...
if (exceptionClass == Throwable.class) {
return -1;
}
return getDepth(exceptionClass.getSuperclass(), depth + 1);
}
根据二:如果getDepth找不到对应的异常类,就从默认实现类DefaultTransactionAttribute.rollbackOn(Throwalbe x)方法进行判断。
@Override
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
DefaultTransactionAttribute判断抛出的异常是RuntimeException或者Error就会进行回滚。说明spring没有对非运行时异常(检查时异常)进行处理,这是因为非运行时异常在编码时,是需要我们开发人员手动去进行try catch进行处理的,也不允许抛出非运行时异常,比如IOException,不然编译器编译都不通过,更别谈运行程序了。
总结:我们规范中要求指定rollbackFor=Exception.class,但是spring中已经包含了RuntimeException的处理,Exception的另一种实现就是非运行时异常,这种我们代码中已经处理了,所以也不需要再去指定。
@Transactional注解真的有必要声明rollbackFor属性吗?的更多相关文章
- JPA中自定义的插入、更新、删除方法为什么要添加@Modifying注解和@Transactional注解?
前几天,有个同事在使用JPA的自定义SQL方法时,程序一直报异常,捣鼓了半天也没能解决,咨询我的时候,我看了一眼他的程序,差不多是这个样子的: @Repository public interface ...
- SpringBoot @Transactional的rollbackFor属性
1.简单回顾Java Exception 该图摘自:https://blog.csdn.net/zhangerqing/article/details/8248186 一方面,我们可以将异常分为运行时 ...
- 事务@Transactional注解的属性
事务的传播行为 当事务方法被另一个事务方法调用时,必须指定事务应该如何传播.例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行.事务的传播行为可以由传播属性指定.Sprin ...
- 数据库事务中的隔离级别和锁+spring Transactional注解
数据库事务中的隔离级别和锁 数据库事务在后端开发中占非常重要的地位,如何确保数据读取的正确性.安全性也是我们需要研究的问题.ACID首先总结一下数据库事务正确执行的四个要素(ACID): 原子性(At ...
- spring事物配置,声明式事务管理和基于@Transactional注解的使用
http://blog.csdn.net/bao19901210/article/details/41724355 http://www.cnblogs.com/leiOOlei/p/3725911. ...
- Spring中的事物管理,用 @Transactional 注解声明式地管理事务
事物: 事务管理是企业级应用程序开发中必不可少的技术, 用来确保数据的 完整性和 一致性. 事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用 事务的四 ...
- spring,mybatis事务管理配置与@Transactional注解使用[转]
spring,mybatis事务管理配置与@Transactional注解使用[转] spring,mybatis事务管理配置与@Transactional注解使用 概述事务管理对于企业应用来说是至关 ...
- spring的@Transactional注解详细用法
概述 事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性.Spring Framework对事务管理提供了一致的抽象,其特点如下: 为不同的事务API提供一致的编程模型, ...
- Spring Boot 中使用 @Transactional 注解配置事务管理
事务管理是应用系统开发中必不可少的一部分.Spring 为事务管理提供了丰富的功能支持.Spring 事务管理分为编程式和声明式的两种方式.编程式事务指的是通过编码方式实现事务:声明式事务基于 AOP ...
随机推荐
- ASP.NET Web 应用 Docker踩坑历程——续
ASP.NET Web 应用 Docker踩坑历程发表后,也开始使用Docker了,然而发布的过程比较痛苦,经常发生下图的事情: 据说是nuget包还原时发生错误 百度了半天也找不到解决的方法,而发生 ...
- python--函数参数传递
1. 调用函数时,实参会传递给形参,叫做参数传递. 2. 根据实际参数的类型不同,函数参数的传递方式可分为 2 种,分别为值传递和引用(地址)传递: 值传递:传递的实参类型为不可变类型(字符串.数字. ...
- Java学习(三)Java起源&发展
目录 Java的诞生 C&C++ Java初生 Java发展(三高: 高可用,高性能,高并发) Java特性和劣势 Java程序运行机制 Java的诞生 C&C++ **1972年 ...
- 使用 Redis 源码编译发布 Windows 版 Redis For Windows 发行包
Redis 是个高性能的键值数据库,现在日常项目开发过程中,目前个人开发项目基本都会用到 Redis,主要是用来做 缓存 和 分布式锁 的底层支持,个人喜欢用 .NET 技术体系,所以一般部署也是用 ...
- linux-0.11分析:boot文件 head.s 第三篇随笔
head.s 参考 [github这个博主的][ https://github.com/sunym1993/flash-linux0.11-talk ] 改变栈顶位置 _pg_dir: startup ...
- springboot整合xxl-job分布式定时任务【图文完整版】
一.前言 定时任务有很多种,有一些大的框架也有一些简单的实现. 比如常见的: JDK的Timer和TimerTask Quartz异步任务调度框架 分布式定时任务XXL-JOB Spring Task ...
- Http 前端向后端传递List参数
场景 在日常项目开发中,前端向后端传参时,可能会遇到需要传 List 类型的参数.比如批量删除时将多个 ID 以集合的形式传给后台. 前端传参 此时前端传参有两种方式: 1.多个同名 key key ...
- linux 3个快捷方式
Ctrl+c组合键:当同时按下键盘上的Ctrl和字母c的时候,意味着终止当前进程的运行.假如执行了一个错误命令,或者是执行某个命令后迟迟无法结束,这时就可以冷静地按下Ctrl+c组合键,命令行终端的控 ...
- [NOI P模拟赛] 传统艺能(子序列自动机、矩阵乘法,线段树)
(2:00)OID:"完了,蓝屏了!"(代码全消失) 众人欢呼 OID:开机,"原题测试--" (30min later)OID 开始传统艺能: " ...
- PHP一句话简单免杀
PHP一句话简单免杀 原型 几种已经开源的免杀思路 拆解合并 <?php $ch = explode(".","hello.ev.world.a.l"); ...