子线程插入数据异常。主子线程全部回滚

该代码示例展示了如何使用Spring的@Transactional注解进行事务管理,并结合CountDownLatch进行多线程操作。在导入Excel数据的过程中,每个子线程处理一部分数据,利用手动事务回滚机制确保数据一致性。如果出现异常,事务会被回滚,并在所有子线程完成后统一给出错误信息。
摘要由CSDN通过智能技术生成
  1. 注入事务管理器

    @Autowired
    private PlatformTransactionManager transactionManager;
  1. 案例代码
    /**
     * 通过excel导入数据
     *
     * @param
     * @param
     * @return
     */
    @RequestMapping(value = "/importExcelOut", method = RequestMethod.POST)
    @Transactional
    public Result<?> importExcelOut(@RequestParam("file") MultipartFile file, Container param) {
        List<Container> containerList = new ArrayList<>();
        AtomicReference<String> errorMessage=new AtomicReference<>();
        try {
            List<ExportContainer> list = super.importExcelNormal(file, ExportContainer.class);
            /*去掉为空值的对象*/
            ExportContainer query = new ExportContainer();
            list=list.stream().filter(p->!query.equals(p)).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(list)) {
                return Result.error("文件中不存在数据");
            }
            //基础数据,用于反向查找
            List<Routes> routesList = routesService.list();
            List<Port> portList = portService.list();
            List<ContainerSize> containerSizeList = containerSizeService.list();
            List<ContainerType> containerTypeList = containerTypeService.list();
            List<CustomerCom> customerComList = customerComService.list();



            SysDepart sysDepart = Optional.ofNullable(sysDepartService.getById(param.getDeptId())).orElse(new SysDepart());
            int a = list.size();
            int count=a%10!=0?(a/10)+1:a/10;
            //主线程
            CountDownLatch mainThreadLatch = new CountDownLatch(count);
            //子线程
            CountDownLatch rollBackLatch  = new CountDownLatch(1);
            AtomicBoolean rollbackFlag=new AtomicBoolean(false);
            ExecutorService executorService = Executors.newFixedThreadPool(count);
            for(int b=0;b<count;b++){
                int c=a-(b*10)>10?(b+1)*10:a;
                List<ExportContainer> expList = list.subList(b*10,c);
                executorService.submit(()->{
                    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
                    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 事物隔离级别,开启新事务,这样会比较安全些。
                    TransactionStatus status = transactionManager.getTransaction(def); // 获得事务状态
                    try {
                        for (ExportContainer container : expList){
                            importExceOutAdd(container,routesList,portList,sysDepart,containerTypeList,containerSizeList,customerComList,containerList);
                        }
                        mainThreadLatch.countDown();
                        rollBackLatch.await();
                        if (rollbackFlag.get()) {
                            transactionManager.rollback(status);
                        }else{
                            transactionManager.commit(status);
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                        mainThreadLatch.countDown();
                        rollbackFlag.set(true);
                        rollBackLatch.countDown();
                        errorMessage.getAndSet(e.getMessage());
                        transactionManager.rollback(status);
                    }
                });
            }
            mainThreadLatch.await();
            rollBackLatch.countDown();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error("文件导入失败:" + e.getMessage());
        } finally {
            try {
                file.getInputStream().close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (StringUtils.isNotBlank(errorMessage.get())){
            return Result.error("文件导入失败:" + errorMessage.get());
        }
        return Result.OK("文件导入成功!数据行数:" + containerList.size());
    }
  1. 代码讲解
    主要是用了两个CountDownLatch控制主子线程的交互。在这里插入图片描述
    01.mainThreadLatch控制主线程的执行,rollBackLatch控制子线程的运行,每运一次子线程mainThreadLatch就减一。当mainThreadLatch减完的时候rollBackLatch减一。子线程就会接着运行。
    在这里插入图片描述
    02.子线程手动事务回滚

事务管理器手动创建事务。捕获异常后手动回滚
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值