java多线程中事务回滚

该代码实现了一个Spring服务接口的实现类,主要功能是处理接收到的请求数据,进行解压、解密,然后使用MyBatis进行数据插入操作。服务中利用了CompletableFuture进行并发处理,分批插入不同表的数据,并进行了事务控制,确保数据一致性。在出现异常时,会进行回滚并返回错误信息。
摘要由CSDN通过智能技术生成
package com.erp.erpApi.service.impl;

import cn.hutool.db.Session;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.erp.business.cbeps.domain.CeasCbepCbeMain;
import com.erp.business.cbeps.mapper.CeasCbepCbeMainMapper;
import com.erp.business.cbeps.service.ICeasCbepCbeMainService;
import com.erp.business.shopee.domain.CeasShopeeMnfBody;
import com.erp.business.shopee.domain.CeasShopeeMnfHead;
import com.erp.business.shopee.domain.CeasShopeeMnfMain;
import com.erp.business.shopee.mapper.CeasShopeeMnfBodyMapper;
import com.erp.business.shopee.mapper.CeasShopeeMnfHeadMapper;
import com.erp.business.shopee.mapper.CeasShopeeMnfMainMapper;
import com.erp.business.shopee.service.ICeasShopeeMnfBodyService;
import com.erp.business.shopee.service.ICeasShopeeMnfHeadService;
import com.erp.business.shopee.service.ICeasShopeeMnfMainService;
import com.erp.common.core.domain.AjaxResult;
import com.erp.common.utils.sign.Base64;
import com.erp.erpApi.domain.RequestDataHead;
import com.erp.erpApi.service.IOmsApi;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.GZIPInputStream;

@Service
public class OmsApiImpl implements IOmsApi {
    @Autowired
    ICeasShopeeMnfMainService ceasShopeeMnfMainService;

    @Autowired
    ICeasShopeeMnfBodyService ceasShopeeMnfBodyService;

    @Autowired
    ICeasShopeeMnfHeadService ceasShopeeMnfHeadService;

    @Autowired
    private ICeasCbepCbeMainService cbepCbeMainService;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Override
    public AjaxResult saveDate(RequestDataHead requestDataHead) {
        int taskCount = 15;
        SqlSession[] sessions = new SqlSession[taskCount];
        try {
            long startTime = System.currentTimeMillis();
            String param = requestDataHead.getParam();
            // 进行解压操作
            byte[] decodedData = Base64.decode(param);
            ByteArrayInputStream inputStream = new ByteArrayInputStream(decodedData);
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            try (GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream)) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = gzipInputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            } catch (IOException e) {
                e.printStackTrace();
                return AjaxResult.error("解压异常,请核验数据后重试!");
            }
            // 获得解压后的加密base64数据
            String decompressedText = new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
            // base64解密获取具体的请求对象
            CeasShopeeMnfMain ceasShopeeMnfMain = JSON.parseObject(decompressedText, CeasShopeeMnfMain.class);
            List<CeasShopeeMnfMain> list = ceasShopeeMnfMainService.list(new QueryWrapper<CeasShopeeMnfMain>()
                    .eq("car_no", ceasShopeeMnfMain.getCarNo())
                    .eq("cess_bill_no", ceasShopeeMnfMain.getCessBillNo()));
            if (list.size() > 0) {
                return AjaxResult.error("该数据已存在,请核验数据后重试!");
            }

            CompletableFuture<Boolean>[] futures = new CompletableFuture[taskCount];
            CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
                    try {
                        sessions[0] = sqlSessionFactory.openSession(false);
                        sessions[0].getConnection().setAutoCommit(false);
                        CeasShopeeMnfMainMapper mapper = sessions[0].getMapper(CeasShopeeMnfMainMapper.class);
                        CeasCbepCbeMainMapper mapper2 = sessions[0].getMapper(CeasCbepCbeMainMapper.class);
                        mapper.insert(ceasShopeeMnfMain);
                        //更新main表平台总金额币制
                        CeasCbepCbeMain cbeMain = cbepCbeMainService.getOne(new QueryWrapper<CeasCbepCbeMain>().eq("bill_no", ceasShopeeMnfMain.getCessBillNo()));
                        if (cbeMain != null) {
                            cbeMain.setPlatformTotalAmount(ceasShopeeMnfMain.getTotalValueUsd());
                            cbeMain.setPlatformCurrency(ceasShopeeMnfMain.getCurrency());
                            mapper2.updateById(cbeMain);
                        }

                    } catch (Exception e) {
                        try {
                            sessions[0].getConnection().rollback();
                        } catch (SQLException ex) {
                            e.printStackTrace();
                        }
                        e.printStackTrace();
                        return false;
                    }
                    return true;
            }, threadPoolTaskExecutor);
            futures[0] = future;

            CompletableFuture<Boolean> future2 = CompletableFuture.supplyAsync(() -> {
                    try {
                        sessions[1] = sqlSessionFactory.openSession(false);
                        sessions[1].getConnection().setAutoCommit(false);
                        CeasShopeeMnfHeadMapper mapper = sessions[1].getMapper(CeasShopeeMnfHeadMapper.class);
                        List<List<CeasShopeeMnfHead>> split = splitList(ceasShopeeMnfMain.getParcelList(), 2500);
                        for (List<CeasShopeeMnfHead> mnfHeads : split) {
                            mapper.insertByList(mnfHeads);
                        }
                    } catch (Exception e) {
                        try {
                            sessions[1].getConnection().rollback();
                        } catch (SQLException ex) {
                            e.printStackTrace();
                        }
                        e.printStackTrace();
                        return false;
                    }
                    return true;
            }, threadPoolTaskExecutor);
            futures[1] = future2;

            List<List<CeasShopeeMnfBody>> lists = splitListBody(ceasShopeeMnfMain.getBodyList(), 250);
            if(lists.size()==1){
                CompletableFuture<Boolean> future3 = CompletableFuture.supplyAsync(() -> {
                    try {
                        sessions[2] = sqlSessionFactory.openSession(false);
                        sessions[2].getConnection().setAutoCommit(false);
                        CeasShopeeMnfBodyMapper mapper = sessions[2].getMapper(CeasShopeeMnfBodyMapper.class);
                        for (List<CeasShopeeMnfBody> shopeeMnfBodies : lists) {
                            mapper.insertBatch(shopeeMnfBodies);
                        }
                    } catch (Exception e) {
                        try {
                            sessions[2].getConnection().rollback();
                        } catch (SQLException ex) {
                            e.printStackTrace();
                        }
                        e.printStackTrace();
                        return false;
                    }
                    return true;
                }, threadPoolTaskExecutor);
                futures[2] = future3;
            }else{
                List<List<List<CeasShopeeMnfBody>>> chunkedLists = splitListByT(lists, taskCount-2);
                for (int i = 2,k=0; i < taskCount; i++,k++) {
                    int finalI = i;
                    int finalK = k;
                    if(chunkedLists.size() < k+1){
                        break;
                    }
                    futures[i] = CompletableFuture.supplyAsync(() -> {
                        try {
                            sessions[finalI] = sqlSessionFactory.openSession(false);
                            sessions[finalI].getConnection().setAutoCommit(false);
                            CeasShopeeMnfBodyMapper mapper = sessions[finalI].getMapper(CeasShopeeMnfBodyMapper.class);
                            for (List<CeasShopeeMnfBody> shopeeMnfBodies : chunkedLists.get(finalK)) {
                                mapper.insertBatch(shopeeMnfBodies);
                            }
                        } catch (Exception e) {
                            try {
                                sessions[finalI].getConnection().rollback();
                            } catch (SQLException ex) {
                                e.printStackTrace();
                            }
                            e.printStackTrace();
                            return false;
                        }
                        return true;
                    }, threadPoolTaskExecutor);
                }

            }

            // 等待所有任务完成
            CompletableFuture<Boolean>[] validFutures = Arrays.stream(futures)
                    .filter(Objects::nonNull)  // 过滤掉 null 元素
                    .toArray(CompletableFuture[]::new);

            CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(validFutures);
            allOfFuture.join();  // 等待所有 CompletableFuture 完成
            for (int i = 0; i < futures.length; i++) {
                if (futures[i]!=null && !futures[i].join()) {
                    for (SqlSession session : sessions) {
                        if (session != null) {
                            session.getConnection().rollback();
                        }
                    }
                    long endTime = System.currentTimeMillis();
                    long executionTimeSeconds = (endTime - startTime) / 1000;
                    System.out.println("OMSApi执行耗时: " + executionTimeSeconds + " 秒");
                    return AjaxResult.error("数据插入异常,请核验数据后重试!");
                }
            }

            for (SqlSession session : sessions) {
                if (session != null) {
                    session.getConnection().commit();
                }
            }
            long endTime = System.currentTimeMillis();
            long executionTimeSeconds = (endTime - startTime) / 1000;
            System.out.println("OMSApi执行耗时: " + executionTimeSeconds + " 秒");
            return AjaxResult.success();
        } catch (JSONException e) {
            e.printStackTrace();
            return AjaxResult.error("参数解析异常,请核验数据后重试!");
        } catch (Exception e) {
            for (SqlSession session : sessions) {
                if (session != null) {
                    session.rollback();
                }
            }
            e.printStackTrace();
            return AjaxResult.error(e.getMessage());
        }finally {
            for (SqlSession session : sessions) {
                if (session != null) {
                    session.close();
                }
            }
        }
    }

    public List<List<CeasShopeeMnfHead>> splitList(List<CeasShopeeMnfHead> list, int batchSize) {
        List<List<CeasShopeeMnfHead>> batches = new ArrayList<>();
        for (int i = 0; i < list.size(); i += batchSize) {
            batches.add(list.subList(i, Math.min(i + batchSize, list.size())));
        }
        return batches;
    }

    public List<List<CeasShopeeMnfBody>> splitListBody(List<CeasShopeeMnfBody> list, int batchSize) {
        List<List<CeasShopeeMnfBody>> batches = new ArrayList<>();
        for (int i = 0; i < list.size(); i += batchSize) {
            batches.add(list.subList(i, Math.min(i + batchSize, list.size())));
        }
        return batches;
    }


    public static <T> List<List<T>> splitListByT(List<T> originalList, int chunkSize) {
        List<List<T>> resultList = new ArrayList<>();

        // 计算平均每份的大小
        int averageChunkSize = originalList.size() / chunkSize;

        // 计算剩余的元素数
        int remainder = originalList.size() % chunkSize;

        // 初始化起始索引
        int startIndex = 0;

        // 拆分成chunkSize份
        for (int i = 0; i < chunkSize; i++) {
            // 计算当前份的大小
            int currentChunkSize = averageChunkSize;

            // 如果有剩余元素,将其平均分配给前面的几份
            if (remainder > 0) {
                currentChunkSize++;
                remainder--;
            }

            // 获取当前份的子列表
            List<T> chunk = originalList.subList(startIndex, startIndex + currentChunkSize);

            // 将当前份添加到结果列表中
            resultList.add(chunk);

            // 更新起始索引
            startIndex += currentChunkSize;
        }

        return resultList;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值