@Transactional
一、作用于接口、接口方法、类以及类方法上
1️⃣当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性。
2️⃣当作用在方法级别时会覆盖类级别的定义。
3️⃣当作用在接口和接口方法时则只有在使用基于接口的代理时它才会生效,也就是 JDK 动态代理,而不是 Cglib 代理。如果正在使用基于类的代理(也就是 CGLIB 代理)时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装,因为注解是不能继承的。
Spring 的建议是在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。
4️⃣当在protected、private或者默认可见性的方法上使用 @Transactional 时是不会生效的,也不会抛出任何异常。
5️⃣默认情况下,只有来自外部的方法调用才会被 AOP 代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用 @Transactional 进行修饰。
二、@Transactional 配置事务失效的场景
1️⃣@Transactional 应用在非 public 修饰的方法上。
注意:protected、private 修饰的方法上使用 @Transactional,虽然事务无效,但不会有任何报错。
2️⃣@Transactional 属性 propagation 设置错误。
这种失效是由于配置错误,若是错误的配置以下三种 propagation,事务将不会发生回滚:
①@Transactional(propagation=Propagation.SUPPORTS)
:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
②@Transactional(propagation=Propagation.NOT_SUPPORTED)
:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
③@Transactional(propagation=Propagation.NEVER)
:以非事务方式运行,如果当前存在事务,则抛出异常。
3️⃣@Transactional 属性 rollbackFor 设置错误。
rollbackFor 可以指定能够触发事务回滚的异常类型。Spring 默认抛出了未检查 unchecked 异常(继承自 RuntimeException 的异常)或者 Error 才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定 rollbackFor 属性。
4️⃣同一个类中方法调用,导致 @Transactional 失效
一个类 Test,它的方法 A(未声明注解事务),调用本类的方法 B(声明有注解事务。不论是 public 的还是 private 的)。外部调用方法 A 之后,方法 B 的事务是不会起作用的。
5️⃣如果异常被try{}catch{}
了,事务就不回滚。如果想让事务回滚必须再往外抛try{}catch{throw new RunTimeException()}
。
如果 B 方法内部抛了异常,而 A 方法此时 try catch 了 B 方法的异常,该事务不能正常回滚。会抛出异常:
org.springframework.transaction.UnexpectedRollbackException:
Transaction rolled back because it has been marked as rollback-only
因为当 B 中抛出了一个异常以后,B 标识当前事务需要 rollback。但是由于 A 手动捕获该异常并进行处理,A 认为当前事务应该正常 commit。此时就出现了前后不一致,也就是因为这样,抛出了前面的UnexpectedRollbackException
。
Spring 的事务是在调用业务方法之前开始的,业务方法执行完毕之后才执行 commit/rollback,事务是否执行取决于是否抛出 RuntimeException。如果抛出 RuntimeException,并在业务方法中没有 catch 的话,事务会回滚。
在业务方法中一般不需要 catch 异常,如果非要 catch 一定要throw new RuntimeException()
,或者注解中指定抛异常类型@Transactional(rollbackFor = Exception.class)
,否则会导致事务失效,数据 commit 造成数据不一致,所以有些时候 try catch 反倒会画蛇添足。
6️⃣数据库引擎不支持事务
事务能否生效,数据库引擎是否支持事务是关键。常用的 MySQL 数据库默认使用支持事务的 Innodb 引擎。一旦数据库引擎切换成不支持事务的 MyISAM,那事务就从根本上失效了。
三、@Transactional 的可用参数
1️⃣readOnly
该属性用于设置当前事务是否为只读事务,设置为 true 表示只读,false 则表示可读写,默认值为 false。
理解:
如果一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持 SQL 执行期间的读一致性。
如果一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询 SQL 必须保证整体的读一致性。否则,在前条 SQL 查询之后,后条 SQL 查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持。
【注意是一次执行多次查询来统计某些信息,这时为了保证数据整体的一致性,要用只读事务】
2️⃣rollbackFor
该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:
- 指定单一异常类:
@Transactional(rollbackFor=RuntimeException.class)
- 指定多个异常类:
@Transactional(rollbackFor={RuntimeException.class,BusinessException.class})
3️⃣rollbackForClassName
该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:
- 指定单一异常类名称:
@Transactional(rollbackForClassName="RuntimeException")
- 指定多个异常类名称:
@Transactional(rollbackForClassName={"RuntimeException","BusnessException"})
4️⃣noRollbackFor
该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。
5️⃣timeout
该属性用于设置事务的超时秒数,默认值为 -1,表示永不超时。
6️⃣propagation
该属性用于设置事务传播行为。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED)
四、基于注解@Transactional的事务
Spring 的事务基础架构代码将默认地只在抛出 RuntimeException 和 unchecked exceptions 时才标识事务回滚。也就是说,当抛出 RuntimeException 或其子类例的实例时(error 也一样)默认标识事务回滚。从事务方法中抛出的 Checked exceptions 将不被标识进行事务回滚。
1️⃣@Transactional 的异常控制,默认是 unChecked Exception 回滚;Checked Exception 不回滚。
2️⃣如果配置了rollbackFor 和 noRollbackFor 且两个都是用同样的异常,那么遇到该异常,还是回滚。
3️⃣rollbackFor 和 noRollbackFor 配置也许不会涵盖所有异常,对于遗漏的按照 unChecked Exception 回滚,Checked Exception 不回滚。
4️⃣让 checked 例外也回滚:
在整个方法前加上@Transactional(rollbackFor=Exception.class)
5️⃣让 unchecked 例外不回滚:
@Transactional(notRollbackFor=RuntimeException.class)
6️⃣不需要事务管理的(只查询的)方法:
@Transactional(propagation=Propagation.NOT_SUPPORTED)
注意:
@Transactional 标识的方法,处理过程尽量的简单。尤其是带锁的事务方法,能不放在事务里面的最好不要放在事务里面。可以将常规的数据库查询操作放在事务前进行,而事务内进行增、删、改、加锁查询等操作。
@Transactional相关推荐
- @Transactional注解最容易忽视的三个失效场景!
@Transactional注解在以下场景中使用,是会失效的,切记! 1.非public方法 spring对注解事务的方法进行校验,修饰符是不是public,不是 public则不会获取@Transa ...
- 3 种场景 @Transactional 失效的解决方法
以下文章来源方志朋的博客,回复"666"获面试宝典 来源 | blog.csdn.net/qq_20597727/article/details/84900994 Transact ...
- Spring官方都推荐使用的@Transactional事务,为啥我不建议使用!
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 事务管理在系统开发中是不可缺少的一部分,Spring提供了 ...
- @aspect注解类不生效_springboot:@Transactional注解 VS @Service注解
1. Transactional注解与Service/Component注解冲突? 之前遇到一个神奇的事情--用Transactional注解的方法,数据处理了一半,后面的数据处理抛出异常后,没有回滚 ...
- Spring Transactional还能导致生产事故?
在Spring中进行事务管理非常简单,只需要在方法上加上注解@Transactional,Spring就可以自动帮我们进行事务的开启.提交.回滚操作.甚至很多人心里已经将Spring事务与@Trans ...
- 一口气说出 6 种 @Transactional 注解的失效场景
一.事务 事务管理在系统开发中是不可缺少的一部分,Spring提供了很好事务管理机制,主要分为编程式事务和声明式事务两种. 编程式事务:是指在代码中手动的管理事务的提交.回滚等操作,代码侵入性比较强, ...
- Spring_Spring@Transactional
Spring事务的传播行为 在service类前加上@Transactional,声明这个service所有方法需要事务管理.每一个业务方法开始时都会打开一个事务. Spring默认情况下会对运行期例 ...
- Spring 事务之@Transactional
在业务代码中,有如下两种情况,比如: throw new RuntimeException("xxxxxxxxxxxx"); 事务回滚 throw new Exception(&q ...
- spring@Transactional注解事务不回滚不起作用无效的问题处理
这几天在项目里面发现我使用@Transactional注解事务之后,抛了异常居然不回滚.后来终于找到了原因. 如果你也出现了这种情况,可以从下面开始排查. 一.特性 先来了解一下@Transactio ...
- SpringBoot之事务管理Transactional
以前学ssh ssm都有事务管理service层通过applicationContext.xml配置,所有service方法都加上事务操作: 用来保证一致性,即service方法里的多个dao操作,要 ...
最新文章
- 如何在企业内部实现云信私有化
- 柑橘有了新农具:湖南30县农业主管与顶级专家共商“AIoT种柑橘”
- mysql实现读写分离
- WPF Slider设置整数
- linux上使用ASP
- 简单的全排列问题(给初学者)
- 量化分析师的python日记_量化分析师的Python日记【第1天:谁来给我讲讲Python?】...
- Android ScrollView 实现整个界面变成列表
- SQL 2008 FileStream数据类型
- C#调用dll代码范例
- vue-router页面传值及接收值
- 【记录】前端代码规范 规范
- 写作技巧 - Markdown常用Emoji表情符号
- js创建a标签下载文件
- 关于CUDA,cuDNN,TF,CUDA驱动版本兼容问题
- MotorSolve(电机设计软件)v5.1绿色中文版
- Photoshop裁剪工具隐藏技巧
- 空头平仓什么意思_外汇空头平仓是什么意思?外汇如何平仓?
- MarkDown图床助手: 截图-传图-生成url 一步到位
- linux运维每天工作内容,Linux运维工作清闲吗?每天需要干什么?
热门文章
- 勿忘初心,继续coding
- 北京市优秀毕业论文—基于车辆轨迹时空数据的城市热点预测模型研究
- avx指令集 matlab,最新版Matlab 2020a修复处理器识别bug 将默认调用最新指令集
- 【JS】1531- 20 个 JS 工具函数助力高效开发
- HTML与CSS实战
- 初识:LevelDB
- Unique Substrings in Wraparound String问题及解法
- 页面数据解析之bs4
- 关于vue的title标签中出现的htmlWebpackPlugin.options.title
- 里程碑4刷Android和Linux双系统教程——win10系统win7虚拟机环境