假如当前正要执行的方法需要一个事务,而当前没有事务,那么就起一个新的事务。
比如说ServiceA.methodA在运行的时候发现自己没有在事务中,它就会为自己分配一个事务。ServiceB.methodB的事务级别也定义为PROPAGATION_REQUIRED, 那么由于执行ServiceA.methodA的时候,ServiceA.methodA已经起了事务,这时在A中调用ServiceB.methodB,ServiceB.methodB看到当前已经有一个在运行的事务ServiceA.methodA ,就不会再起新的事务而是加入到A的事务中去。这样,在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都会被回滚。即使ServiceB.methodB的事务已经被提交,但是ServiceA.methodA在接下来要回滚,ServiceB.methodB也要回滚
PROPAGATION_REQUIRES_NEW
当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的事务,等待ServiceB.methodB的事务完成以后ServiceA.methodA才继续执行。它与PROPAGATION_REQUIRED 的事务区别在于是要共用一个事务还是要相互独立,要是需要事务的相互独立互不影响,即各自回滚就使用NEW。因为ServiceB.methodB是独立于A的事务,所以就算在A中调用了B,且B抛异常失败回滚,但是也不影响A的执行,同样A失败了也不影响B的结果不会回滚B。
事务的传播属性问题
今天看到一个账务处理中处理失败更新代扣交易流水状态,然后立即抛出异常回滚。以为是错误,后来问过别人后,自己又看了看,突然发现是自己错了。在网上查了一下事务的传播属性发现自己把这两个给弄错了。记录一下。
同时在网上看到有说调用同类的方法事务处理错误的情况,关于这一点是因为同一个类中的方法调用无法使用aop,当我们调用第一个方法时使用的是Spring的AOP代理,但是当你在第一个方法中调用另一个方法时时直接跳转到第二个方法,这样就没有使用代理无法使用事务。
比如一个业务类中有方法batchMethod() ,但是batchMethod()中调用了同一个业务类中的处理方法handleDKRecord(),handleDKRecord()方法有事务Propagation.REAUIRES_NEW,那么在batchMethod直接调用handleDKRecord方法进行处理时目的是每调用一次就开启一个事务,通过这样的方式来保证如果有一条数据处理失败则返回相应参数供记录或者进行当前事务的回滚,而不是因为一条数据处理的失败就影响整个批处理,将整个批处理回滚。但是当你在batchMethod方法中调用handleDKRecord方法时会发现无法开启事务。
处理方法是在第一个方法batchMethod() 中获取当前的代理对象,然后再通过代理对象调用其他方法,这样才能保证添加到方法上的@Transactional生效。
Propagation.REQUIRED