场景

项目需要 导入一批数据,对数据进行切割,用多线程跑。

问题点

方法上增加@Transactional,对多线程无效,发生异常,子线程不会回滚,即使在子线程中增加@Transactional。
原因:线程不归spring容器管理,也就不指望通知回滚了。

上代码

1.将大数据进行切割

 // apache自带切割api, num是对应想要切几段
ListUtils.partition(list, num);

2、使用异常标志、发令枪控制各线程回滚

@Transactional(rollbackFor = Exception.class)
public Result<String> dealData(int sheetMergeCount) {
		// todo 业务逻辑...
		// 切割数据
        List<List<Integer>> list = splitList(sheetMergeCount, 10);
        // 异常标志,AtomicBoolean保证线程安全
        AtomicBoolean isError = new AtomicBoolean(false);
        // 发令枪,长度是切割的子集合数量
        CountDownLatch countDownLatch = new CountDownLatch(list.size());
        for (List<Integer> integerList : list) {
        	// 将任务放进线程池
            ThreadPoolUtil.exec(() -> {
            	// 将事务操作放在新的类中,并开启事务
                extraService.upload(integerList, isError, countDownLatch);
            });
        }
        try {
        	// 等所有线程都跑完,判断异常标识,有异常,进行主线程内回滚
            countDownLatch.await();
            if (isError.get()) {
            	// 手动回滚
            	TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.fail("系统异常,稍后重试");
            }
            return Result.success("success");
        } catch (Exception e) {
	        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.error("dealData发令枪异常", e);
        }
        return Result.fail("系统异常,稍后重试");
    }
@Service
@Slf4j
public class ExtraServiceImpl implements ExtraService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uploadData(List<Integer> integerList, AtomicBoolean isError, CountDownLatch countDownLatch) {
        try {
            // todo 业务逻辑
        } catch (Exception e) {
            log.error("ExtraService.uploadData异常", e);
            // 发生异常,进行标记
            isError.set(true);
        } finally {
        	// 发令枪倒计时
            countDownLatch.countDown();
        }
        try {
        	// 等所有线程都跑完,判断异常标识,有异常,线程内进行回滚
            countDownLatch.await();
            if (isError.get()) {
                // 手动回滚
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
        } catch (Exception e) {
            log.error("ExtraService.uploadData发令枪异常", e);
            // 手动回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }
}

ok!!!希望能帮到您,麻烦点个赞

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐