springboot多线程情况下控制事务

    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;
    List<TransactionStatus> transactionStatuses = Collections.synchronizedList(new ArrayList<>());
 
 
 
 
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void testMultiThreadTransactional() throws BizException {
 
        //模拟总数据
        List<SysUserAddress> sysUserAddresses = ListUtil.toList();
        for (int i = 0; i < 10000; i++) {
            sysUserAddresses.add(new SysUserAddress(null, "上海市" + (i + 1), "上海市", "浦东新区"));
        }
 
        //线程数,按线程数拆分,默认3个线程
        int threadCount = 3;
        //按线程数平均分配后,每个线程处理的数据量
        int perThreadData = sysUserAddresses.size() / threadCount;
        //按线程数平均分配后,多余的数据量
        int remainderCount = sysUserAddresses.size() % threadCount;
        //有多余的数据,再开个线程处理
        boolean havingRemainder = remainderCount > 0;
        if (havingRemainder) {
            threadCount += 1;
        }
 
        //子线程倒计锁
        CountDownLatch threadLatchs = new CountDownLatch(threadCount);
        //子线程中是否有异常标识
        AtomicBoolean isError = new AtomicBoolean(false);
 
        try {
            for (int i = 0; i < threadCount; i++) {
                //设置每个线程处理的数据量,多余的数据放在最后一个线程中处理
                List<SysUserAddress> splitList = sysUserAddresses.stream()
                        .skip((long) i * perThreadData)
                        .limit((i == threadCount - 1) ? (havingRemainder ? remainderCount : perThreadData) : perThreadData)
                        .collect(Collectors.toList());
 
                //开启多线程
                executorService.execute(() -> {
                    try {
                        try {
                            this.sysUserAddressService.saveSysUserAddressByTransaMan(dataSourceTransactionManager, transactionStatuses, splitList);
                        } catch (Throwable e) {
                            e.printStackTrace();
                            isError.set(true);
                        } finally {
                            threadLatchs.countDown();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        isError.set(true);
                    }
                });
            }
 
            // 倒计锁设置超时时间 30s
            boolean await = threadLatchs.await(300, TimeUnit.SECONDS);
            // 判断是否超时
            if (!await) {
                isError.set(true);
                log.error("等待子线程执行已经超时!");
            }
        } catch (Throwable e) {
            e.printStackTrace();
            isError.set(true);
        }
 
        if (CollUtil.isNotEmpty(transactionStatuses)) {
            if (isError.get()) {
                transactionStatuses.forEach(status -> {
                    if (!status.isCompleted()) {
                        dataSourceTransactionManager.rollback(status);
                    }
                });
            } else {
                transactionStatuses.forEach(status -> {
                    if (!status.isCompleted()) {
                        dataSourceTransactionManager.commit(status);
                    }
                });
            }
        }
 
        System.out.println("主线程完成!");
 
    }
 
 
 
 
 
 
 
 
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void saveSysUserAddressByTransaMan(PlatformTransactionManager transactionManager, List<TransactionStatus> transactionStatuses, List<SysUserAddress> sysUserAddressList) {
        if (CollUtil.isEmpty(sysUserAddressList)) {
            return;
        }
 
        //将事务状态都放在同一个事务里面
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(Propagation.REQUIRES_NEW.value());                   // 事物隔离级别,每个线程都开启新事务,会比较安全一些
        TransactionStatus transactionStatus = transactionManager.getTransaction(def);   // 获得事务状态
        transactionStatuses.add(transactionStatus);
 
        sysUserAddressList.forEach(obj -> {
//            if (StrUtil.equals(obj.getProvince(), "上海市2")) {
//                //模拟子线程中保存出现异常
//                int i = 1 / 0;
//            }
            synchronized (obj) {
                save(obj);
            }
        });
        System.out.println("子线程:" + Thread.currentThread().getName());
    }

引用:SpringBoot项目中控制线程池、多线程事务提交、回滚的方式_spring多线程事务回滚_拄杖忙学轻声码的博客-CSDN博客

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值