开发中常用多线程异步操作场景解决方案
创始人
2025-05-31 19:30:59

场景一:批量操作,事务控制部分回滚

第一步:创建现场池,注意不同业务场景线程池队列等参数不一样,根据实际业务场景来 

package org.jeecg.modules.pUser.excutor;import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;/*** @version 1.0* @Author zhaozhiqiang* @Date 2022/8/18 14:56* @Description //TODO  职业病团队批量导入线程池配置*/
@Slf4j
@Configuration
@EnableAsync// 启用异步任务 151-500
public class PeUserThreadPoolConfig implements AsyncConfigurer {public static void main(String[] args) {System.out.println(Runtime.getRuntime().availableProcessors());}/*** @version 1.0* @Author zhaozhiqiang* @Date 2022/8/19 10:59* @Description //TODO 团队批量预登记*/@Bean("teamImportExecutor")public ThreadPoolTaskExecutor teamImportTaskExecutor() {ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();// 设置核心线程数threadPoolTaskExecutor.setCorePoolSize(Runtime.getRuntime().availableProcessors());// 设置最大线程数threadPoolTaskExecutor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);// 设置队列容量,当没有足够的线程去处理任务时,可以将任务放进队列中,以队列先进先出的特性来执行工作任务threadPoolTaskExecutor.setQueueCapacity(5000);// 设置线程活跃时间(秒)非核心线程数 还回去的时间  如果空闲超过10秒就被回收threadPoolTaskExecutor.setKeepAliveSeconds(1);// 设置默认线程名称threadPoolTaskExecutor.setThreadNamePrefix("teamImport_");//用来设置线程池关闭的时候等待所有任务都完成(可以设置时间)threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);//设置上面的时间(秒)threadPoolTaskExecutor.setAwaitTerminationSeconds(1);//拒绝策略:线程池都忙不过来的时候,可以适当选择拒绝/*** ThreadPoolExecutor.AbortPolicy();//默认,队列满了丢任务抛出异常* ThreadPoolExecutor.DiscardPolicy();//队列满了丢任务不异常* ThreadPoolExecutor.DiscardOldestPolicy();//将最早进入队列的任务删,之后再尝试加入队列* ThreadPoolExecutor.CallerRunsPolicy();//如果添加到线程池失败,那么主线程会自己去执行该任务*/threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());threadPoolTaskExecutor.initialize();return threadPoolTaskExecutor;}/*** @version 1.0* @Author zhaozhiqiang* @Date 2022/8/19 11:00* @Description //TODO 批量发布申请单*/@Bean("releaseBatchOrderExecutor")public ThreadPoolTaskExecutor releaseBatchOrderTaskExecutor() {ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();// 设置核心线程数threadPoolTaskExecutor.setCorePoolSize(2);// 设置最大线程数threadPoolTaskExecutor.setMaxPoolSize(4);// 设置队列容量,当没有足够的线程去处理任务时,可以将任务放进队列中,以队列先进先出的特性来执行工作任务threadPoolTaskExecutor.setQueueCapacity(30);// 设置线程活跃时间(秒)非核心线程数 还回去的时间  如果空闲超过10秒就被回收threadPoolTaskExecutor.setKeepAliveSeconds(1);// 设置默认线程名称threadPoolTaskExecutor.setThreadNamePrefix("releaseBatch_");//用来设置线程池关闭的时候等待所有任务都完成(可以设置时间)threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);//设置上面的时间(秒)threadPoolTaskExecutor.setAwaitTerminationSeconds(60);//拒绝策略:线程池都忙不过来的时候,可以适当选择拒绝/*** ThreadPoolExecutor.AbortPolicy();//默认,队列满了丢任务抛出异常* ThreadPoolExecutor.DiscardPolicy();//队列满了丢任务不异常* ThreadPoolExecutor.DiscardOldestPolicy();//将最早进入队列的任务删,之后再尝试加入队列* ThreadPoolExecutor.CallerRunsPolicy();//如果添加到线程池失败,那么主线程会自己去执行该任务*/threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());threadPoolTaskExecutor.initialize();return threadPoolTaskExecutor;}
}

第二步:团队批量预登记使用如下(当前场景比较复杂,适用于大批量数据并且事务控制是按照部分回滚的;比如100条中有三条错误那么只回滚这三条的数据)

1 控制层代码/*** 批量登记** @return*/@ApiOperation(value = "批量预登记", notes = "批量预登记")@PostMapping(value = "/preBatchRegist")public Result preBatchRegist(@RequestParam(value = "ids", required = true) String ids)  {String token = UserTokenContext.getToken();peTeamImportService.preBatchRegist(ids,token);return Result.ok("批量登记成功,结果将陆续执行,请耐心等待所有数据全部执行完成");}
2实现层代码
@Override@Async("teamImportExecutor")public void preBatchRegist(String ids,String token) {UserTokenContext.setToken(token);if (StringUtils.isBlank(ids)) {log.info("批量预登记ids为空");return;}//1 查询数据库组装需要预登记的数据List list = Arrays.asList(ids.split(","));//将list集合按指定长度进行切分,返回新的List>集合List> idsSplitNumber = Lists.partition(list, BATCH_LIMIT_NUMBER);List peTeamImportPages = new ArrayList<>();idsSplitNumber.forEach(item -> {List peTeamImports = this.listByIds(item);List selfStrings = new ArrayList();peTeamImports.forEach(mainBean -> {selfStrings.add(mainBean.getId());});if (selfStrings.size() > 0) {//获取单位导入受检史List mainIds = peTeamImportSelfService.getMainIds(selfStrings);peTeamImports.forEach(mainItem -> {PeTeamImportPage vo = new PeTeamImportPage();BeanUtils.copyProperties(mainItem, vo);List childDto = new ArrayList<>();mainIds.forEach(childItem -> {if (StringUtils.equals(mainItem.getId(), childItem.getMainId())) {childDto.add(childItem);}});vo.setPeTeamImportSelfList(childDto);peTeamImportPages.add(vo);});}});if (peTeamImportPages.size() > 0) {//2 开始预登记for (int i = 0; i < peTeamImportPages.size(); i++) {try {peTeamImportSelfService.prebatchSend(peTeamImportPages.get(i));} catch (Exception e) {continue;}}}}
3 新事物控制实现类,当前控制新事务,单个有问题单个回滚
@Override@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)public void prebatchSend(PeTeamImportPage dto) {try {//预登记之前不能重复登记PeTeamImport byId = peTeamImportService.getById(dto.getId());if (null != byId && byId.getRegistFlag() == 1) {//已预登记过了不能重复登记log.info("编号:{},已经预登记了不能重复登记", dto.getId());throw new JeecgBootException("已经预登记了不能重复登记");}//2 往分组中添加人员信息,必须是为收费的批次,收费是不能添加人员信息的LambdaQueryWrapper departWrapper = new LambdaQueryWrapper<>();departWrapper.eq(PeDepart::getDelFlag, 0);departWrapper.eq(PeDepart::getId, dto.getDepartId());departWrapper.eq(PeDepart::getPayStatus, PeCommonConstant.UNPAID);PeDepart departOne = peDepartService.getOne(departWrapper);if (null == departOne) {log.info("改批次已经缴费或者退费:[{}]", dto.getDepartId());throw new JeecgBootException("改批次已经缴费或者退费");}//3.1分组名称和分组套餐必须先配置好,先判断库里分组是否存在、分组套餐是否已经被启用LambdaQueryWrapper groupWrapper = new LambdaQueryWrapper<>();groupWrapper.eq(PeDepartGroup::getDepartId, dto.getDepartId());groupWrapper.eq(PeDepartGroup::getGroupName, dto.getGroupName());groupWrapper.eq(PeDepartGroup::getDelFlag, 0);groupWrapper.eq(PeDepartGroup::getUseFlag, 1);groupWrapper.gt(PeDepartGroup::getTotalPrice, 0);//分组价格大于0PeDepartGroup groupOne = peDepartGroupService.getOne(groupWrapper);if (null == groupOne) {log.info(PeCodeConstant.DISABLE_IMPORT_GROUP_MSG);throw new JeecgBootException("改分组已经缴费或者退费");} else {//3.2 分组当前必须配置好套餐有项目可以检查LambdaQueryWrapper groupDetailsWrapper = new LambdaQueryWrapper<>();groupDetailsWrapper.eq(PeDepartGroupDetail::getGroupId, groupOne.getId());groupDetailsWrapper.eq(PeDepartGroupDetail::getDiseasesFlag, 1);groupDetailsWrapper.eq(PeDepartGroupDetail::getDelFlag, 0);List groupDetails = peDepartGroupDetailService.list(groupDetailsWrapper);if (null == groupDetails || groupDetails.size() == 0) {//当前分组没有配置套餐无法预登记log.info(PeCodeConstant.DISABLE_IMPORT_GROUP_ITEMS_MSG);throw new JeecgBootException(PeCodeConstant.DISABLE_IMPORT_GROUP_ITEMS_MSG);}}//4添加登记表、登记详情表、用户表等String peNumber = peRegistService.getPeNumber();//通过分组编号获取单位批次编号和单位批次名称PeUserInfo peUserInfo = null;try {peUserInfo = new PeUserInfo(0, dto.getName(), dto.getPhone(), null, dto.getDepartId(), dto.getSex(),dto.getMarriage(), dto.getIdno(), "" + dto.getAge(), departOne.getCompanyName());} catch (Exception e) {e.printStackTrace();log.info("用户相关信息填写不规范:[{}]", e.getMessage());throw new JeecgBootException("用户相关信息填写不规范");}//保存到体检用户表中userInfoService.save(peUserInfo);PeRegist build = new PeRegist();//工种类型需要转义成字典值if (StringUtils.isNotBlank(dto.getHazardType())) {String hazardTypeValue = formatHazardType(dto.getHazardType());if (StringUtils.isNotBlank(hazardTypeValue)) {build.setWorkeType(hazardTypeValue);}}build.setPeType(PeCommonConstant.REAM_TYPE);build.setPeNumber(peNumber);build.setPeUserId(peUserInfo.getId());build.setName(dto.getName());build.setOrderTime(departOne.getOrderTime());build.setPeDepartId(dto.getDepartId());build.setGroupId(groupOne.getId());build.setGroupName(dto.getGroupName());build.setPackDisFlag(PeCommonConstant.DIS_GROUP_TYPE);build.setCurRate(departOne.getDiscount());//单位折扣和个人的保持一直,为了个人和团队统一费用统计核算功能build.setSource(PeCommonConstant.WINDOW_REGISTER);//转义岗位状态if (StringUtils.isNotBlank(dto.getPosStatus())) {if (StringUtils.equals(dto.getPosStatus(), PeCommonConstant.POS_STATUS_PRE_STR)) {//上岗前build.setPosStatus(PeCommonConstant.POS_STATUS_PRE);} else if (StringUtils.equals(dto.getPosStatus(), PeCommonConstant.POS_STATUS_ZG_STR)) {//在岗期间build.setPosStatus(PeCommonConstant.POS_STATUS_ZG);} else if (StringUtils.equals(dto.getPosStatus(), PeCommonConstant.POS_STATUS_LG_STR)) {//离岗build.setPosStatus(PeCommonConstant.POS_STATUS_LG);}}build.setRemarks(PeCommonConstant.DISABLE_IMPORT_REMARKS);peRegistService.save(build);//成功之后更新导入标识已成功PeTeamImport entity = new PeTeamImport();entity.setId(dto.getId());entity.setRegistFlag(1);entity.setRegId(build.getId());peTeamImportService.updateById(entity);//查询单位批次分组信息List packgeInfoVos = peDepartGroupDetailService.queryCombInfoById(groupOne.getId());addRegistInfo(groupOne.getId(), build, packgeInfoVos);//添加当前人员项目对应的所有科室id多个逗号隔开String combDepartIds = peRegistMapper.getCombDepartIds(build.getId());build.setDepartIds(combDepartIds);peRegistService.updateById(build);//5添加职业病相关的表//插入职业病危害因素种类//判断数据库是否已经存在数据try {//转化空格String str = dto.getHazardName().replaceAll("\\s*", "");//将中文逗号转化英文逗号String finalStr = str.replaceAll(",", ",");String finalconsDetailStr = "[" + finalStr + "]";PeIndusConsDetailFactor detailFactor = new PeIndusConsDetailFactor(1, dto.getDepartId(), build.getId(), dto.getHazardCategory(), finalconsDetailStr);LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();wrapper.eq(PeIndusConsDetailFactor::getDelFlag, 0);wrapper.eq(PeIndusConsDetailFactor::getRegId, dto.getId());wrapper.eq(PeIndusConsDetailFactor::getIndusDepartId, dto.getDepartId());wrapper.eq(PeIndusConsDetailFactor::getDisType, 1);wrapper.eq(PeIndusConsDetailFactor::getFactorName, dto.getHazardCategory());PeIndusConsDetailFactor detailFactor1 = indusConsDetailFactorMapper.selectOne(wrapper);if (null == detailFactor1) {if (StringUtils.isNotBlank(dto.getHazardCategory()) && StringUtils.isNotBlank(dto.getHazardName())) {indusConsDetailFactorMapper.insert(detailFactor);}} else {detailFactor.setId(detailFactor1.getId());indusConsDetailFactorMapper.updateById(detailFactor);}} catch (Exception e) {e.printStackTrace();throw new JeecgBootException(e.getMessage());}//职业历史 indusConsDetailHistoryMapperLambdaQueryWrapper historyLambdaQueryWrapper = new LambdaQueryWrapper<>();historyLambdaQueryWrapper.eq(PeIndusConsDetailHistory::getRegId, build.getId());indusConsDetailHistoryMapper.delete(historyLambdaQueryWrapper);//受检本人历史先查看预分组信息中当前人的信息是否存在List peTeamImportSelfList = this.selectByMainId(dto.getId());if (null != peTeamImportSelfList && peTeamImportSelfList.size() > 0) {peTeamImportSelfList.stream().forEach(item -> {PeIndusConsDetailHistory history = new PeIndusConsDetailHistory(1, dto.getDepartId(), build.getId(), item.getCycletime(),item.getHarmFactor(), item.getProtectMeasures(), item.getUnit(), item.getWorkshop(), item.getWorktype());if (StringUtils.isNotBlank(item.getCycletime()) && StringUtils.isNotBlank(item.getHarmFactor()) && StringUtils.isNotBlank(item.getProtectMeasures())&& StringUtils.isNotBlank(item.getUnit()) && StringUtils.isNotBlank(item.getWorkshop()) && StringUtils.isNotBlank(item.getWorktype())) {indusConsDetailHistoryMapper.insert(history);}});}//慢性病历史 indusConsDetailCommonMapperLambdaQueryWrapper commonLambdaQueryWrapper = new LambdaQueryWrapper<>();commonLambdaQueryWrapper.eq(PeIndusConsDetailCommon::getRegId, build.getId());indusConsDetailCommonMapper.delete(commonLambdaQueryWrapper);if (StringUtils.isNotBlank(dto.getPastHistory()) || StringUtils.isNotBlank(dto.getSlowName()) || StringUtils.isNotBlank(dto.getOther())) {PeIndusConsDetailCommon consDetailCommon = new PeIndusConsDetailCommon(1, dto.getDepartId(), build.getId(), dto.getPastHistory(), dto.getSmokeStatus(), dto.getDrinkStatus(), dto.getSmokeAmount(), dto.getSmokeLength(), dto.getFirst(), dto.getCycle(), dto.getPeriod(), dto.getStop(), dto.getChildren(), dto.getFlow(),dto.getEarly(), dto.getDie(), dto.getAbnormal(), dto.getOther(), dto.getDrinkAmount(), dto.getDrinkLenth(), dto.getSlowName(), dto.getSlowTime(), dto.getSlowDepart(), dto.getHealthFlag());indusConsDetailCommonMapper.insert(consDetailCommon);}//症状 indusConsDetailDiseaseMapperLambdaQueryWrapper detailDiseaseLambdaQueryWrapper = new LambdaQueryWrapper<>();detailDiseaseLambdaQueryWrapper.eq(PeIndusConsDetailDisease::getIndusDepartId, dto.getDepartId());detailDiseaseLambdaQueryWrapper.eq(PeIndusConsDetailDisease::getRegId, build.getId());indusConsDetailDiseaseMapper.delete(detailDiseaseLambdaQueryWrapper);//转化空格String consDetailStr = dto.getSymptom().replaceAll("\\s*", "");//将中文逗号转化英文逗号String detailStr = consDetailStr.replaceAll(",", ",");//用集合包裹起来if (StringUtils.isNotBlank(dto.getSymptom())) {detailStr = "[" + detailStr + "]";PeIndusConsDetailDisease disease = new PeIndusConsDetailDisease(1, dto.getDepartId(), build.getId(), detailStr);indusConsDetailDiseaseMapper.insert(disease);}} catch (Exception e) {log.info("异常了:" + e.getMessage());throw e;}

第三步:批量发布申请单和批量预登记是一个场景,只不过当前的没有上面那个复杂,数据量不是很多

    @Override@Async("releaseBatchOrderExecutor")public void releaseBatchOrder(String regIds,String token) {UserTokenContext.setToken(token);if (StringUtils.isNotBlank(regIds)) {List list = Arrays.asList(regIds.split(","));if (null != list && list.size() > 0) {for (int i = 0; i < list.size(); i++) {try {log.info("登记编号:{}", list.get(i));peLisContactService.batchSend(list.get(i));} catch (Exception e) {log.info("异常信息:{}", e.getMessage());continue;}}}}}@Override@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)public void batchSend(String regId) {try {//先判断是否lis那边已经推送过了String hosId = peChargeMapper.getHosId();//业务处理log.info("departFeeHandler regId:{} ", regId);//同步数据库和lis对接List peLisContacts = peLisContactMapper.queryListByRegId(regId, hosId);log.info("开始执行:{}条", peLisContacts.size());if (null != peLisContacts && peLisContacts.size() > 0) {log.info("开始插入条数:{}", peLisContacts.size());//批量插入this.saveBatch(peLisContacts);}} catch (Exception e) {log.info("异常了:" + e.getMessage());throw e;}}

场景二:批量操作,不用控制事务(比如发短信,发飞秋,插入日志等场景)

package org.jeecg.common.util;import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;/*** @version 1.0* @Author zhaozhiqiang* @Date 2023/2/13 16:58* @Description //TODO 客服线程池*/
@Slf4j
@Configuration
@EnableAsync// 启用异步任务 151-500
public class CsThreadPoolConfig implements AsyncConfigurer {public static void main(String[] args) {System.out.println(Runtime.getRuntime().availableProcessors());}/*** @version 1.0* @Author zhaozhiqiang* @Date 2022/8/19 10:59* @Description //TODO频率高将队列容量设置30*/@Bean("feiqiuTask")public ThreadPoolTaskExecutor feiqiuTask() {ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();// 设置核心线程数threadPoolTaskExecutor.setCorePoolSize(Runtime.getRuntime().availableProcessors());// 设置最大线程数threadPoolTaskExecutor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);// 设置队列容量,当没有足够的线程去处理任务时,可以将任务放进队列中,以队列先进先出的特性来执行工作任务threadPoolTaskExecutor.setQueueCapacity(30);// 设置线程活跃时间(秒)非核心线程数 还回去的时间  如果空闲超过10秒就被回收threadPoolTaskExecutor.setKeepAliveSeconds(1);// 设置默认线程名称threadPoolTaskExecutor.setThreadNamePrefix("feiqiu_");//用来设置线程池关闭的时候等待所有任务都完成(可以设置时间)threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);//设置上面的时间(秒)threadPoolTaskExecutor.setAwaitTerminationSeconds(10);//拒绝策略:线程池都忙不过来的时候,可以适当选择拒绝/*** ThreadPoolExecutor.AbortPolicy();//默认,队列满了丢任务抛出异常* ThreadPoolExecutor.DiscardPolicy();//队列满了丢任务不异常* ThreadPoolExecutor.DiscardOldestPolicy();//将最早进入队列的任务删,之后再尝试加入队列* ThreadPoolExecutor.CallerRunsPolicy();//如果添加到线程池失败,那么主线程会自己去执行该任务*/threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());threadPoolTaskExecutor.initialize();return threadPoolTaskExecutor;}/*** 发送短信* 频率高将队列容量设置100* @return*/@Bean("smsSendTask")public ThreadPoolTaskExecutor smsSendTask() {ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();// 设置核心线程数threadPoolTaskExecutor.setCorePoolSize(Runtime.getRuntime().availableProcessors());// 设置最大线程数threadPoolTaskExecutor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);// 设置队列容量,当没有足够的线程去处理任务时,可以将任务放进队列中,以队列先进先出的特性来执行工作任务threadPoolTaskExecutor.setQueueCapacity(100);// 设置线程活跃时间(秒)非核心线程数 还回去的时间  如果空闲超过10秒就被回收threadPoolTaskExecutor.setKeepAliveSeconds(1);// 设置默认线程名称threadPoolTaskExecutor.setThreadNamePrefix("feiqiu_");//用来设置线程池关闭的时候等待所有任务都完成(可以设置时间)threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);//设置上面的时间(秒)threadPoolTaskExecutor.setAwaitTerminationSeconds(10);//拒绝策略:线程池都忙不过来的时候,可以适当选择拒绝/*** ThreadPoolExecutor.AbortPolicy();//默认,队列满了丢任务抛出异常* ThreadPoolExecutor.DiscardPolicy();//队列满了丢任务不异常* ThreadPoolExecutor.DiscardOldestPolicy();//将最早进入队列的任务删,之后再尝试加入队列* ThreadPoolExecutor.CallerRunsPolicy();//如果添加到线程池失败,那么主线程会自己去执行该任务*/threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());threadPoolTaskExecutor.initialize();return threadPoolTaskExecutor;}
}
  @Override@Async("feiqiuTask")public void sendFeiqiuSmg(String title, HttpServletRequest request, String msg, String userId, String token) {UserTokenContext.setToken(token);//发送feiqiu消息String userName = JwtUtil.getUserNameByToken(request);LoginUser user = sysUserService.getEncodeUserInfo(userName);if (null != user) {try {SysUser sendUserInfo = sysUserService.getById(userId);if (null != sendUserInfo && StringUtils.isNotBlank(sendUserInfo.getClientId())) {FeiQiuUtils.send(title, userName, sendUserInfo.getClientId(), msg);log.info("发送飞秋消息成功:{}", msg);}} catch (IOException e) {e.printStackTrace();log.error("发送飞秋消息失败:{}", msg);}}}

场景三:批量操作,控制事务全部回滚(注意:不推荐这样做)

不推荐这样做的原因主要有三

1 要么全部成功要么全部失败,特别耗费连接资源数据量大的时候其它场景操作当前的表的时候等待,有可能操作死表

2 这这场景用的很少,或者几乎不用

3 这种场景后台进程特别耗时,失去了大批量异步的意义

把场景一稍微改造一下就是场景三,循环放到新事物里面就是全部滚回

场景四:批量操作,控制事务遇到错误立马停止,错误之前的不用回滚

 当前的场景使用频率还是蛮高的,改造场景一将for循环的continue改成break就完了

 

相关内容

热门资讯

绿萝施什么肥料长得好,绿萝最好... 绿萝施什么肥料长得好目录绿萝施什么肥料长得好绿萝最好的肥料是啥绿萝施什么肥?绿萝用什么肥料长得快 让...
古剑奇谭3开场动画及结局剧情分... 古剑奇谭3开场动画及结局剧情分析目录古剑奇谭3开场动画及结局剧情分析古剑奇谭3开头怎么那么长仙剑3的...
新华字典中方字的笔划顺序是什么... 新华字典中方字的笔划顺序是什么目录新华字典中方字的笔划顺序是什么方子的笔画中国汉字的总方针是先上,后...
和地球最相似的星球叫什么,最像... 和地球最相似的星球叫什么目录和地球最相似的星球叫什么最像地球的星球与地球最相似的星球叫什么?和地球最...
什么是几九,几九是什么意思 极... 什么是几九目录什么是几九几九是什么意思今天是几九了啊,一九,二九,三九,四九,五九,是什么意思什么是...
东北都有什么特色小零食啊,东北... 东北都有什么特色小零食啊目录东北都有什么特色小零食啊东北特产零食东北特色小吃东北三省各自有什么特色零...
化妆棉的作用有哪些,化妆棉的作... 化妆棉的作用有哪些目录化妆棉的作用有哪些化妆棉的作用化妆棉有什么作用?化妆棉的作用有哪些 1....
六道有哪六道,火影忍者六道能力... 六道有哪六道目录六道有哪六道火影忍者六道能力六道轮回,都有哪六道?六道是指哪六道?六道有哪六道 ...
飞信手机多方通话怎么用(飞信手... 本篇文章极速百科给大家谈谈飞信手机多方通话怎么用,以及飞信手机好友收费吗对应的知识点,希望对各位有所...
会计中的流动资产包括哪些,下列... 会计中的流动资产包括哪些目录会计中的流动资产包括哪些下列会计科目中,属于流动资产的是(  )。会计基...
旺旺碎冰冰是什么梗的简单介绍 ... 本篇文章极速百科给大家谈谈旺旺碎冰冰是什么梗,以及对应的知识点,希望对各位有所帮助,不要忘了收藏本站...
怎样给芭比做衣服,给芭比娃娃做... 怎样给芭比做衣服目录怎样给芭比做衣服给芭比娃娃做衣服怎么做不用缝怎样帮芭比娃娃做衣服怎样给芭比做衣服...
如何区分,植物油,矿物油,白油... 本篇文章极速百科给大家谈谈如何区分,植物油,矿物油,白油,液蜡?,以及怎么区别植物油和矿物油对应的知...
武汉空气为什么那么差(为什么武... 本篇文章极速百科给大家谈谈武汉空气为什么那么差,以及为什么武汉空气质量这么差对应的知识点,希望对各位...
美国4大全尺寸皮卡之一,性能不... 本篇文章极速百科给大家谈谈美国4大全尺寸皮卡之一,性能不输福特猛禽,通用塞拉...,以及美国皮卡车品...
skp是啥(SKP是啥格式) ... 本篇文章极速百科给大家谈谈skp是啥,以及SKP是啥格式对应的知识点,希望对各位有所帮助,不要忘了收...
C1的教练资格证要怎么考,c1... C1的教练资格证要怎么考目录C1的教练资格证要怎么考c1教练资格证怎么考取怎么考c1汽车教练资格证?...
经典一词中的典是什么意思,经典... 经典一词中的典是什么意思目录经典一词中的典是什么意思经典的典是什么意思经典的典是什么意思?请问金典和...
什么叫做商,什么是商? 极速百... 什么叫做商目录什么叫做商什么是商?除法算式里的商是什么意思什么是商?什么叫做商 “商”的含义可...
柯南伦敦告白小兰是哪一集,名侦... 柯南伦敦告白小兰是哪一集目录柯南伦敦告白小兰是哪一集名侦探柯南哪集新一在伦敦向 小兰表白?名侦探柯南...
9个复韵母是哪9个韵母,六个单... 9个复韵母是哪9个韵母目录9个复韵母是哪9个韵母六个单韵母,九个复韵母,九个鼻韵母和十六个整体认读音...
如何去除猫尿味,怎样才能去除猫... 如何去除猫尿味目录如何去除猫尿味怎样才能去除猫尿的味道???并且让猫猫不会再乱尿?帮帮忙,如何去除猫...
吉他有多少和弦都是什么,吉他有... 吉他有多少和弦都是什么目录吉他有多少和弦都是什么吉他有多少和弦 都是什么吉他一共有多少和弦啊?听别人...
网上怎么订购好利来蛋糕(如何订... 本篇文章极速百科给大家谈谈网上怎么订购好利来蛋糕,以及如何订购好利来蛋糕对应的知识点,希望对各位有所...
杭州重点高中有哪些,杭州有哪些... 杭州重点高中有哪些目录杭州重点高中有哪些杭州有哪些重点高中杭州哪所高中最好杭州重点高中有哪些 ...
女为悦己者容意思,士为知己者死... 女为悦己者容意思目录女为悦己者容意思士为知己者死,女为悦己者容.是什么意思.女人无需为悦己者容悦人不...
北戴河是海吗 极速百科网 极速... 北戴河是海吗目录北戴河是海吗北戴河是海吗 北戴河是海。北戴河古称渝水,清光绪年间,因沙河流经戴...
外婆是什么样的关系,姥姥与我的... 外婆是什么样的关系目录外婆是什么样的关系姥姥与我的关系叫什么关系姥姥是指外婆还是奶奶??我与外婆是什...
头歌--第1关:Linux文件... 任务描述 假设系统中存在一个文件File,修改该文件的权限,根据实际需求...
【Spring从成神到升仙系列... 👏作者简介:大家好,我是爱敲代码的小黄,独...