• 多线程事务回滚示例代码


        //注入线程池和事务管理器
        @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();
        }
    
    
    
  • 相关阅读:
    mybatis学习$与#号取值区别
    java学习
    mybatis学习
    spring mvc 数据校验(bean实体注解实现)
    maven学习
    java.lang.ClassNotFoundException: org.springframework.web.util.WebAppRootListener
    20180804 excel规划求解。。。
    java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
    mybatis config 配置设置说明
    进程状态以及状态转换
  • 原文地址:https://www.cnblogs.com/juyss/p/16195218.html
Copyright © 2020-2023  润新知