很久沒寫部落格了,大概是目前這份工作本身就能讓我學到挺多東西吧,是以沒去寫部落格了,希望以後的自己,隻要工作内容是開發就要保持一個月至少一篇的部落格吧。
>
之前寫過一篇文章是關于spring事物的傳播行為的。
>
今天這篇文章主要是将RROPAGATION_REQUIRES_NEW傳播行為在實際項目中的使用。該事物會開啟一個新的事物也就是建立一個事物和之前的事物沒有任何關系。
關于PROPAGATION_REQUIRED和RROPAGATION_REQUIRES_NEW的差別,我之前的文章也有。
>
在項目中如果做過提現操作的話,就會知道一般提現都是異步的需要經過以下幾個步驟:
1:使用者申請提現,扣除賬戶餘額,并且記錄交易流水
2:将資料發送給第三方支付機構(一般隻有第三方支付機構和銀行才有權動使用者銀行卡的)
3:定時任務查詢提現處理狀态。根據查詢狀态處理提現結果。
比如當扣除賬戶餘額和記錄交易流水記錄必須在同一個事物裡面,也就是說這兩操作要麼同時成功要麼同時失敗。否則會存在扣了錢找不到記錄的嚴重問題。這是不允許的。這裡隻需要對這個操作加上事物即可滿足要求。
對于第三個,因為一般都是批量操作的,比如當提現失敗的時候,需要将原來的提現記錄标記為失敗,并且增加一條提現失敗復原的記錄,增加賬戶餘額等操作,這裡就不能把所有的批量操作放置到一個事物中,不然會出大問題,比如前面10個使用者都處理成功了,最後一個處理失敗,隻能復原最後一個,而不能全部復原,這裡就需要使用RROPAGATION_REQUIRES_NEW事物的傳播行為了,開啟一個新的事物。
注意這裡開發的時候遇到一個坑,因為Spring的事物實作是基于aop動态代理的,主要的代理實作機制有Java動态代理和CGLIB代理。一開始我們以為在同一個Service中a方法調用b方法,b方法加上事物。b方法使用REQUIRES_NEW模式,測試發現後不起作用,這裡面應該是跟代理機制有關。正确的使用方法時ServiceA的a方法調用ServiceB的B方法才管用。
例子如下:
@Service
public class WithdrawJobServiceImpl implements WithdrawJobService {
@Autowired
private WithdrawService withdrawService;
@Override
public void dealWithdrawResult() {
// 每次處理100條資料 從資料庫中查詢待處理的提現記錄
List<UserCommRecordVo> commRecordVos = null;
for (int i = ; i < commRecordVos.size(); i++) {
//批量處理
//向第三方查詢提現處理結果 需要try catch一條處理失敗不能影響其他任務
withdrawService.dealWithdrawOrder();
}
}
}
@Service
public class WithdrawServiceImpl implements WithdrawService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
dealWithdrawOrder(){
//處理提現結果
}
}