多线程事务回滚示例代码

    //注入线程池和事务管理器
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private DataSourceTransactionManager transactionManager;

    /**
     * 这里使用了线程池,异步执行保存商品清单和生成订单操作,由此引发了多线程事务回滚问题和多线程SecurityContext传递问题,具体解决办法看代码
     * 如果出现了其他的新问题,实在解决不了,可以转为串行执行,业务代码已在注释标注
     * @param bo 定标申请新增业务对象
     * @return 操作结果
     */
    public Boolean insertByBoSync(TenderCalibrationBo bo){
        //线程计数器
        CountDownLatch countDownLatch = new CountDownLatch(2);
        //线程报错标记
        AtomicBoolean isError = new AtomicBoolean(false);
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus status = transactionManager.getTransaction(def);
        //类转换
        TenderCalibration add = BeanUtil.toBean(bo, TenderCalibration.class);
        validEntityBeforeSave(add);
        //查询商品清单
        Long recordId = bo.getRecordId();
        TenderRecordVo tenderRecordVo = tenderRecordService.queryById(recordId);
        List<TenderRecordGoodsVo> tenderRecordVoGoodsList = tenderRecordVo.getGoodsList();
        Assert.notEmpty(tenderRecordVoGoodsList,"所属定标记录商品清单不存在,请核对");
        List<TenderCalibrationGoodsBo> goodsList = BeanCopyUtils.copyList(tenderRecordVoGoodsList, TenderCalibrationGoodsBo.class);
        try {
            //保存操作
            save(add);
        } catch (Exception e) {
            log.info("主线程报错{}",e.getMessage());
            isError.set(true);
            e.printStackTrace();
        }
        bo.setGoodsList(goodsList);
        if (!isError.get()) {
            SecurityContext context = SecurityContextHolder.getContext();
            //获取定标id
            Long id = add.getId();
            //批量新增
            threadPoolTaskExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    log.info("商品清单保存线程任务开始执行");
                    //为新线程赋值SecurityContext
                    SecurityContextHolder.setContext(context);
                    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
                    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
                    TransactionStatus status = transactionManager.getTransaction(def);
                    try {
                        //批量保存商品清单
                        //这里是实际业务执行代码,如果多线程问题解决不了,需要串行执行的话,直接拿这行代码即可
                        tenderCalibrationGoodsService.saveBoBatch(goodsList,id);
                    } catch (Exception e) {
                        log.info("商品清单保存线程报错{}",e.getMessage());
                        isError.set(true);
                        e.printStackTrace();
                    }
                    countDownLatch.countDown();
                    try {
                        countDownLatch.await();
                        SecurityContextHolder.clearContext();
                        if (isError.get()){
                            log.info("商品清单保存回滚");
                            transactionManager.rollback(status);
                        }else {
                            log.info("商品清单保存提交");
                            transactionManager.commit(status);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    log.info("商品清单保存线程执行完毕");
                }
            });
            //生成订单
            threadPoolTaskExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    log.info("订单生成线程任务开始执行");
                    //为新线程赋值SecurityContext
                    SecurityContextHolder.setContext(context);
                    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
                    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
                    TransactionStatus status = transactionManager.getTransaction(def);
                    try {
                        //生成订单
                        //这里是实际业务执行代码,如果多线程问题解决不了,需要串行执行的话,直接拿这行代码即可
                        createOrder(bo,tenderRecordVo);
                    } catch (Exception e) {
                        log.info("订单生成线程报错{}",e.getMessage());
                        isError.set(true);
                        e.printStackTrace();
                    }
                    countDownLatch.countDown();
                    try {
                        countDownLatch.await();
                        SecurityContextHolder.clearContext();
                        if (isError.get()){
                            log.info("订单生成线程回滚");
                            transactionManager.rollback(status);
                        }else {
                            log.info("订单生成线程提交");
                            transactionManager.commit(status);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    log.info("订单生成线程执行完毕");
                }
            });
            try {
                countDownLatch.await();
                if (isError.get()){
                    log.info("主线程回滚");
                    transactionManager.rollback(status);
                }else {
                    log.info("主线程提交");
                    transactionManager.commit(status);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("主线程执行完毕");
        }
        return !isError.get();
    }


posted @ 2022-04-26 16:09  juyss  阅读(566)  评论(0编辑  收藏  举报