项目场景:
定时任务处理已经逾期的订单,在for循环里面对每个订单处理后单独事务提交,不影响整体事务问题描述:
定时任务执行时发现并未实现在循环时处理完一个就提交,单独的事务未生效。 定时任务直接调用的外层service类大致的代码: @Transactional(rollbackFor = Exception.class)
public void overdueRepayProcess() {
List<BsiLoanOrder> forbidList = new ArrayList<>();// 逾期订单列表
// 省略查询逾期订单的逻辑
/* 逾期订单处理 */
if (CollectionUtil.isEmpty(forbidList)) {
return;
}
int num = 0;
for (BsiLoanOrder order : forbidList) {
/* 使用锁机制,处理订单时不能让用户进行操作 */
boolean lockFlag = LockDoorUtil.setKey(LOCK_KEY_PREFIX + order.getId());
try {
if(!lockFlag) {
continue;
}
// service类内部方法,逾期订单处理
this.forbidListProcess(order);
num++;
} catch (Exception e) {
log.error("【逾期订单" + order.getId() + "处理】报错", e);
} finally {
LockDoorUtil.delKey(LOCK_KEY_PREFIX + order.getId(), lockFlag);
}
}
}
/**
* 逾期订单处理(单独事务)
*/
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void forbidListProcess(BsiLoanOrder order) {
// 省略内部逻辑
}
原因分析:
用spring声明式事务,最外层方法直接调用该类的内部方法是不会走到代理类的,也就是不会走到切面,所以forbidListProcess方法上的@Transactional会失效解决方案:
把forbidListProcess方法写在新的service类里即可。/**
* 逾期订单处理服务类
*/
@Service
public class LoanOverdueProcessService {
/**
* 逾期订单处理(单独事务)
*/
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void forbidListProcess(BsiLoanOrder order) {
// 省略内部逻辑
}
}
外层service类里面
// service类内部方法,逾期订单处理
this.forbidListProcess(order);
改为
// 单独事务不影响循环
loanOverdueProcessService.forbidListProcess(order);
再次运行定时任务,循环一个就提交一次事务,问题解决