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;
}
}
java多线程中事务回滚
于 2023-07-24 08:58:27 首次发布
该代码实现了一个Spring服务接口的实现类,主要功能是处理接收到的请求数据,进行解压、解密,然后使用MyBatis进行数据插入操作。服务中利用了CompletableFuture进行并发处理,分批插入不同表的数据,并进行了事务控制,确保数据一致性。在出现异常时,会进行回滚并返回错误信息。
摘要由CSDN通过智能技术生成