本文旨在探讨同一类中,方法相互调用对Spring事务注解生效与否的影响。
假设
类A有a,b两个方法:
a方法由public修饰,在执行时会调用b方法;
b方法由private修饰,在执行时会对数据库进行操作。
场景
场景1
a方法调用b方法,a方法无事务注解修饰,此时无论b方法有无事务注解修饰,事务都将失效;
场景2
a方法调用b方法,a方法有事务注解修饰,那么方法a的事务会生效,并且对于方法b中抛出的异常也会回滚。此时b方法如果有事务注解修饰,b方法的事务失效。
原因分析
从外部调用其他类的方法时,如果使用事务注解修饰了目标方法,那么在spring扫描bean的时候会将包含@Transactional的方法生成一个包装好的代理类,并使用AOP在方法执行前开启事务,在执行后提交/回滚事务。但类内部之间的方法调用是不走这套逻辑的,所以不会有代理对象,也就不会启动事务。
解决办法
- 加入父方法的事务:类A中的方法a调用方法b时,可以在a上加入注解,用于管理a方法与b方法共同的事务。
- 在方法里使用编程式事务:
//引入事务模板
@Autowired
TransactionTemplate transactionTemplate;
//在b方法(被调方法)中使用模板创建并执行语句
transactionTemplate.execute((TransactionCallback<Void>) status -> {
// 业务逻辑
return null;
})
- 获取当前类的代理对象,使用代理对象调用b方法
- 注入自身,使用注入后的对象调用b方法
- 通过spring上下文获取到当前代理类,使用代理类调用b方法
- 使用AopContext获取到当前代理类,使用代理类调用b方法
延申
不同类之间方法调用的逻辑
类A的方法a调用类B的方法b,只要方法a 或 b配置了事务,此时事务会生效。
若两个方法都配置了事务,两个事务具体以何种方式传播,取决于设置的事务传播特性。spring事务的默认方式是 REQUIRED(有事务则加入,没有则创建),在这种情况下,如果方法a和b都加了@Transactional注解,因为是a调用b,那么b方法会加入到a方法的事务中执行。
spring事务传播特性
REQUIRED(Spring默认的事务传播类型 required:需要、依赖、依靠):如果当前没有事务,则自己新建一个事务,如果当前存在事务则加入这个事务
当A调用B的时候:如果A中没有事务,B中有事务,那么B会新建一个事务;如果A中也有事务、B中也有事务,那么B会加入到A中去,变成一个事务,这时,要么都成功,要么都失败。(假如A中有2个SQL,B中有两个SQL,那么这四个SQL会变成一个SQL,要么都成功,要么都失败)
SUPPORTS(supports:支持;拥护):当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行
如果A中有事务,则B方法的事务加入A事务中,成为一个事务(一起成功,一起失败),如果A中没有事务,那么B就以非事务方式运行(执行完直接提交);
MANDATORY(mandatory:强制性的):当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常。
如果A中有事务,则B方法的事务加入A事务中,成为一个事务(一起成功,一起失败);如果A中没有事务,B中有事务,那么B就直接抛异常了,意思是B必须要支持回滚的事务中运行
REQUIRES_NEW(requires_new:需要新建):创建一个新事务,如果存在当前事务,则挂起该事务。
B会新建一个事务,A和B事务互不干扰,他们出现问题回滚的时候,也都只回滚自己的事务;
NOT_SUPPORTED(not supported:不支持):以非事务方式执行,如果当前存在事务,则挂起当前事务
被调用者B会以非事务方式运行(直接提交),如果当前有事务,也就是A中有事务,A会被挂起(不执行,等待B执行完,返回);A和B出现异常需要回滚,互不影响
NEVER(never:从不): 如果当前没有事务存在,就以非事务方式执行;如果有,就抛出异常。就是B从不以事务方式运行
A中不能有事务,如果没有,B就以非事务方式执行,如果A存在事务,那么直接抛异常
NESTED(nested:嵌套的)嵌套事务:如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样(开启一个事务)
如果A中没有事务,那么B创建一个事务执行,如果A中也有事务,那么B会会把事务嵌套在里面
参考文章
https://blog.csdn.net/ChineseSoftware/article/details/127602310
https://blog.csdn.net/single_0910/article/details/121561725
https://blog.csdn.net/dayuiicghaid/article/details/125260092
https://blog.csdn.net/hellozhxy/article/details/109753711