同类不同方法相互调用时的@Transactional失效问题

本文旨在探讨同一类中,方法相互调用对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在方法执行前开启事务,在执行后提交/回滚事务。但类内部之间的方法调用是不走这套逻辑的,所以不会有代理对象,也就不会启动事务。

解决办法

  1. 加入父方法的事务:类A中的方法a调用方法b时,可以在a上加入注解,用于管理a方法与b方法共同的事务。
  2. 在方法里使用编程式事务:
//引入事务模板
@Autowired
TransactionTemplate transactionTemplate;

//在b方法(被调方法)中使用模板创建并执行语句
transactionTemplate.execute((TransactionCallback<Void>) status -> {
	// 业务逻辑
	return null;
})
  1. 获取当前类的代理对象,使用代理对象调用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

你可能感兴趣的:(后端杂谈,java,spring)