Spring 事务的坑

直接上代码:

@Service
@Slf4j
public class FinanceWithDrawRecordServiceImpl extends BaseServiceImpl implements FinanceWithDrawRecordService {
    
    @Transactional
    public BaseResponse autoWithdraw(Long bigLogId) {
           //.....省略一大片代码

           this.createAccountingReceivableItem(financeBidLog.getOrderId());
   
    }

    @Transactional
    private void createAccountingReceivableItem(Long orderId){
        try {
           
                //生成台账
                accountingReceivableItemService.createAccountingReceivableItem(financePayment);
            }
        } catch (Exception ex){
            log.error("订单id{}提现生成台账失败,", orderId, ex);
        }
    }
}

@Service
public class AccountingReceivableItemServiceImpl extends BaseServiceImpl
        implements AccountingReceivableItemService {

    @Transactional
    public BaseResponse createAccountingReceivableItem(FinancePayment payment) {
        throw new FinanceException("ex");

    }
}

几个坑:

  1. 通过 this 调用当前类方法,被调用的方法本身没事务,只有调用方本身有事务。所以需要 try catch 代码块处理异常,不影响被调用方的事务。

  2. 示例依然会抛异常回滚。因为 AccountingReceivableItemServiceImpl 的 createAccountingReceivableItem 方法是由 Spring Bean 管理的,这里 FinanceWithDrawRecordServiceImpl 调用 accountingReceivableItemService.createAccountingReceivableItem 方法,虽然由 try - catch 代码块抱住,但是 Spring 还是会抛出一个 UnexpectedRollbackException ;

下面看下 Spring 的源码:

    protected Object invokeWithinTransaction(Method method, Class targetClass, final InvocationCallback invocation)
            throws Throwable {

        // If the transaction attribute is null, the method is non-transactional.
        final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
        final PlatformTransactionManager tm = determineTransactionManager(txAttr);
        final String joinpointIdentification = methodIdentification(method, targetClass);

        if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
            // Standard transaction demarcation with getTransaction and commit/rollback calls.
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
            Object retVal = null;
            try {
                // This is an around advice: Invoke the next interceptor in the chain.
                // This will normally result in a target object being invoked.
                retVal = invocation.proceedWithInvocation();
            }
            catch (Throwable ex) {
                // target invocation exception
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            }
            finally {
                cleanupTransactionInfo(txInfo);
            }
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }

        
    }

可以看到 Spring 的事务切面在原来的代码外面包了层 try-catch 代码块,在 completeTransactionAfterThrowing 方法里面先抛出了一个 UnexpectedRollbackException ,在把原异常对象 ex 抛出。所以总的事务还是回滚了。

你可能感兴趣的:(Spring 事务的坑)