Spring嵌套事物,事物的传播之REQUIRES_NEW

时间:2022-09-08 11:58:59

很久没写博客了,大概是目前这份工作本身就能让我学到挺多东西吧,所以没去写博客了,希望以后的自己,只要工作内容是开发就要保持一个月至少一篇的博客吧。
>
之前写过一篇文章是关于spring事物的传播行为的。
>
今天这篇文章主要是将RROPAGATION_REQUIRES_NEW传播行为在实际项目中的使用。该事物会开启一个新的事物也就是创建一个事物和之前的事物没有任何关系。
关于PROPAGATION_REQUIRED和RROPAGATION_REQUIRES_NEW的区别,我之前的文章也有。
Spring嵌套事物,事物的传播之REQUIRES_NEW
Spring嵌套事物,事物的传播之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 = 0; i < commRecordVos.size(); i++) {
//批量处理
//向第三方查询提现处理结果 需要try catch一条处理失败不能影响其他任务
withdrawService.dealWithdrawOrder();
}
}
}
@Service
public class WithdrawServiceImpl implements WithdrawService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
dealWithdrawOrder(){
//处理提现结果
}
}