直接上代碼:
@Service
@Slf4j
public class FinanceWithDrawRecordServiceImpl extends BaseServiceImpl<FinanceWithdrawRecord> implements FinanceWithDrawRecordService {
@Transactional
public BaseResponse<Void> autoWithdraw(Long bigLogId) {
//.....省略一大片代碼
this.createAccountingReceivableItem(financeBidLog.getOrderId());
}
@Transactional
private void createAccountingReceivableItem(Long orderId){
try {
//生成臺(tái)賬
accountingReceivableItemService.createAccountingReceivableItem(financePayment);
}
} catch (Exception ex){
log.error("訂單id{}提現(xiàn)生成臺(tái)賬失敗,", orderId, ex);
}
}
}
@Service
public class AccountingReceivableItemServiceImpl extends BaseServiceImpl<AccountingReceivableItem>
implements AccountingReceivableItemService {
@Transactional
public BaseResponse<Void> createAccountingReceivableItem(FinancePayment payment) {
throw new FinanceException("ex");
}
}
幾個(gè)坑:
通過(guò) this 調(diào)用當(dāng)前類方法种玛,被調(diào)用的方法本身沒(méi)事務(wù)程储,只有調(diào)用方本身有事務(wù)。所以需要 try catch 代碼塊處理異常辽剧,不影響被調(diào)用方的事務(wù)送淆。
示例依然會(huì)拋異常回滾怕轿。因?yàn)?AccountingReceivableItemServiceImpl 的 createAccountingReceivableItem 方法是由 Spring Bean 管理的偷崩,這里 FinanceWithDrawRecordServiceImpl 調(diào)用 accountingReceivableItemService.createAccountingReceivableItem 方法辟拷,雖然由 try - catch 代碼塊抱住,但是 Spring 還是會(huì)拋出一個(gè) 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 的事務(wù)切面在原來(lái)的代碼外面包了層 try-catch 代碼塊阐斜,在 completeTransactionAfterThrowing 方法里面先拋出了一個(gè) UnexpectedRollbackException 衫冻,在把原異常對(duì)象 ex 拋出。所以總的事務(wù)還是回滾了谒出。