场景
项目需要 导入一批数据,对数据进行切割,用多线程跑。
问题点
方法上增加@Transactional,对多线程无效,发生异常,子线程不会回滚,即使在子线程中增加@Transactional。
原因:线程不归spring容器管理,也就不指望通知回滚了。
代码
将大数据进行切割
ListUtils.partition(list, num);
|
使用异常标志、发令枪控制各线程回滚
@Transactional(rollbackFor = Exception.class) public Result<String> dealData(int sheetMergeCount) { List<List<Integer>> list = splitList(sheetMergeCount, 10); 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 { } 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(); } } }
|
引用博客
https://blog.csdn.net/gsc1456/article/details/124748943
其他参考
https://blog.csdn.net/u010978399/article/details/117771620
- 这篇博客也是使用发令枪的方式实现子线程回滚,不同的是,该博客中每个子线程的事务是除了回滚是手动的外,提交也是手动的。
- 这篇博客声明了两个计数器,一个主线程的,一个子线程的。当主线程的计数器归零,子线程的发令枪才开枪,子线程才会执行事务判断的部分,实现效果和当前代码我认为是没有区别的