@Transactional注解失效,大致会有以下几种场景:
数据库引擎是否支持事务(Mysql 的 MyIsam引擎不支持事务);
注解所在的类是否被加载为 Bean(是否被spring 管理);
注解所在的方法是否为 public 修饰的;(spring要求被代理的方法必须是public)
方法用final修饰,spring的事务基于AOP实现,通过动态代理生成代理类,被final修饰的方法不能被重写,所以不能代理final方法
是否存在自身调用的问题;
所用数据源是否加载了事务管理器;
@Transactional的扩展配置propagation是否正确。
多线程调用,spring的事务是通过数据库连接实现的,事务管理内部使用threadLocal,不同线程间数据库连接就不是同一个了,所以不在同一事务
调用本类的方法
1 A方法有事务,B没有,以A的事务执行,不管是A发生异常或者B发生异常,AB均回滚
2 A方法无事务,B有,AB都无法回滚
3 A有,B有,均以A的事务执行
如果B方法异常被捕获没有抛出,那仅当B发生异常时,整个事务失效,A无法知道B发生异常,所以AB均不会回滚;
调用外部类的方法(A类 B类)
- A有事务,B也有事务,各自使用各自的事务
A调用B方法,B异常,A不捕获,那么AB都会回滚
A调用B方法,B异常,A捕获了调用B的异常,那么AB也会回滚
抛出如下异常 Transaction rolled back because it has been marked as rollback-only;数据库中数据也没有被修改。总结一下,spring boot 默认的事物即发生异常无论是否捕获均会回滚。 - A有事务,B无事务,C有事务(A类调用外部B类,B调用外部C类)
C发生异常,B进行捕获了。但最终A B C 全部回滚了
抛出如下异常 Transaction rolled back because it has been marked as rollback-only;数据库中数据也没有被修改。总结一下,spring boot 默认的事物即发生异常无论是否捕获均会回滚。 - A.a有事务,B.a无事务,B.b有事务(A类调用B.a,B.a调用B.b)
B.b发生异常,在B.a中进行捕获,最终都commit了,A.a无感知,正常了走完了整个流程。只有B.b异常位置没有往下执行,在B.b方法内的前面的语句还是commit了
B.a无事务,调用同类的有异常的事务,会被自动忽略,因此直接认为B.a跟B.b无事务,在含有事务的A那里是没有感知到有异常发生,因此commit了 - A有事务,B没有,以A的事务执行,AB均回滚,先正常调用b()且b()有增删改操作,但是接着执行a()的动库操作异常,则两个方法内动库操作全部回滚;
- A无事务,B有,正常执行中a()的动库操作,然后执行类B的方法b()的动库操作发生异常,那么b()中的事务操作会全部回滚,但是并不会影响先前a()中的操作,即b()中异常b()回滚,a()不回滚。
事务传播机制
1) PROPAGATION_REQUIRED ,Spring默认的事务传播级别,使⽤该级别的特点是,如果上下⽂中已经存在事务,那么就加⼊到事务中执⾏,如果当前上下⽂中不存在事务,则新建事务执⾏。所以这个级别通常能满⾜处理⼤多数的业务场景。
2)PROPAGATION_SUPPORTS ,如果上下⽂存在事务,则⽀持事务加⼊事务,如果没有事务,则使⽤⾮事务的⽅式执⾏。所以说,并⾮所有的包在transactionTemplate.execute中的代码都会有事务⽀持。这个通常是⽤来处理那些并⾮原⼦性的⾮核⼼业务逻辑操作。应⽤场景较少。
3)PROPAGATION_MANDATORY , 该级别的事务要求上下⽂中必须要存在事务,否则就会抛出异常!配置该⽅式的传播级别是有效的控制上下⽂调⽤代码遗漏添加事务控制的保证⼿段。⽐如⼀段代码不能单独被调⽤执⾏,但是⼀旦被调⽤,就必须有事务包含的情况,就可以使⽤这个传播级别。
4)PROPAGATION_REQUIRES_NEW ,每次都要⼀个新事务,该传播级别的特点是,每次都会新建⼀个事务,并且同时将上下⽂中的事务挂起,执⾏当前新建事务完成以后,上下⽂事务恢复再执⾏。
这是⼀个很有⽤的传播级别,举⼀个应⽤场景:现在有⼀个发送100个红包的操作,在发送之前,要做⼀些系统的初始化、验证、数据记录操作,然后发送100封红包,然后再记录发送⽇志,发送⽇志要求100%的准确,如果⽇志不准确,那么整个⽗事务逻辑需要回滚。
怎么处理整个业务需求呢?就是通过这个PROPAGATION_REQUIRES_NEW 级别的事务传播控制就可以完成。发送红包的⼦事务不会直接影响到⽗事务的提交和回滚。
5)PROPAGATION_NOT_SUPPORTED ,当前级别的特点就是上下⽂中存在事务,则挂起事务,执⾏当前逻辑,结束后恢复上下⽂的事务。
这个级别有什么好处?可以帮助你将事务极可能的缩⼩。我们知道⼀个事务越⼤,它存在的⻛险也就越多。所以在处理事务的过程中,要保证尽可能的缩⼩范围。举⼀个应⽤场景:⽐如⼀段代码,是每次逻辑操作都必须调⽤的,⽐如循环1000次的某个⾮核⼼业务逻辑操作。这样的代码如果包在事务中,势必造成事务太⼤,导致出现⼀些难以考虑周全的异常情况。所以这个事务这个级别的传播级别就派上⽤场了。⽤当前级别的事务模板抱起来就可以了。
6)PROPAGATION_NEVER ,⽽PROPAGATION_NEVER传播级别要求上下⽂中不能存在事务,⼀旦有事务,就抛出runtime异
常,强制停⽌执⾏!这个级别上辈⼦跟事务有仇。
7)PROPAGATION_NESTED ,该传播级别特征是,如果上下⽂中存在事务,则嵌套事务执⾏,如果不存在事务,则新建事务