高并发接口实现、大数据批量插入、修改、删除优化

Java8实现高并发接口

 private LinkedBlockingDeque<Request> queue = new LinkedBlockingDeque();
 
 @Data
 class Request{
     UseLogDto dto;
     CompletableFuture<Integer> future;
     public Request(AppUseLogDto dto,CompletableFuture<Integer> future){
         this.dto = dto;
         this.future = future;
     }
 }

 public int saveLog(UseLogDto logDto) throws Exception {
    //并发队列
    CompletableFuture<Integer> future = new CompletableFuture();
    Request request = new Request(logDto,future);
    queue.add(request);
    
    return future.get();//阻塞:将响应分发到具体的线程
 }

 @Async
 @Scheduled(cron = "*/2 * * * * ?")
 public void logTask() throws Exception {
    int status = 0;
    //避免jvm回收request,future需要做回调
    List<Request> requests = new ArrayList<>();
    try {
        int size = queue.size();
        log.info("扫描发队列长度:" + size);
        if (size == 0){
            return;
        }
        List<AppUseLogDto> list = new ArrayList<>();
        for (int i = 0;i < size;i++){
            Request request = queue.poll();
            AppUseLogDto dto = request.getDto();
            //获取部门信息
            String userId = dto.getUserId();
            EmpUser empUser = cacheEmpUser.get(userId);
            if (empUser == null){
                List<EmpUser> empUserList = empUserMapper.checkDeptTree(null, userId);
                if (!CollectionUtils.isEmpty(empUserList)){
                    empUser = empUserList.get(0);
                    //缓存部门数据
                    cacheEmpUser.put(empUser.getStaffNoOld(),empUser);
                }
            }
            String deptCode = empUser != null ? empUser.getDepartCode() : null;
            String deptName = empUser != null ? empUser.getDepartName() : null;
            dto.setDeptId(deptCode);
            dto.setDeptName(deptName);
            list.add(dto);
            //避免jvm回收request,future需要做回调
            requests.add(request);
        }
        //响应通知
        status = appUseLogMapper.batchAdd(list);
    }catch (Exception e){
        log.error("请求队列处理发生异常:{}",e);
    }finally {
        if (requests.size() > 0){
            for (Request request : requests) {
                request.getFuture().complete(status);
            }
        }
    }
 }

多线程批量插入20w数据30秒完成

 public int batchAddHistory(){
    List<AppUseLogDto> list = select();
    if (CollectionUtils.isEmpty(list)) {
        return 0;
    }
    //线程池初始参数、mybatis批量插入算法
    int count = 500;
    int size = list.size();
    int nThreads = size % count == 0 ? size / count : size / count + 1;
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    List<Future<Integer>> futures = new ArrayList<>();
    for (int i = 0; i < nThreads; i++) {
        int start = i * count;
        int end = (i + 1) * count;
        Callable<Integer> task = () -> {
            //手动开启事务
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
            TransactionStatus status = transactionManager.getTransaction(def);
            List<String> ids = null;
            try {
                //拆分集合
                List<AppUseLogDto> AppUseLogs = list.subList(start, end > size ? size : end);
                ids = AppUseLogs.stream().map(dto -> dto.getId()).collect(Collectors.toList());
                //同步主表app_use_log数据到历史表
                appUseLogMapper.batchAddHistory(AppUseLogs);
                // 提交事务
                transactionManager.commit(status);
            } catch (Exception e) {
                // 回滚事务
                transactionManager.rollback(status);
                log.error("同步数据失败:",e);
                log.error("主表app_use_log同步失败,Ids[:" + ids + "]");
                throw new RuntimeException("主表app_use_log同步失败,Ids[:" + ids + "]");
            }
            return 1;
        };
        futures.add(executorService.submit(task));
    }
    //关闭线程池
    executorService.shutdown();
    if (!futures.isEmpty()) {
        return nThreads;
    }
    return 0;
 }

存在数据则更新,不存在数据则新增

 public int saveOrUpdate(List<MeteReal> list) {
     if (!CollectionUtils.isEmpty(list)){
         task.execute(() -> {
             int size = list.size();
             long l = System.currentTimeMillis();
             meteRealMapper.saveOrUpdate(list);
             long e = System.currentTimeMillis();
             log.info( "mysql 执行 on DUPLICATE KEY UPDATE 修改" + size + "条数据,共耗时:" + (e - l) + "毫秒");
         });
     }
     return 1;
 }

saveOrUpdate方法mapper实现

 <insert id="saveOrUpdate" parameterType="java.util.List">
     insert into m_signal_real_data(SignalID,SignalValue,ReportTime) values
     <foreach collection="list" item="item" separator=",">
         (#{item.signalId}, #{item.value}, #{item.dateTime})
     </foreach>
     on DUPLICATE KEY UPDATE SignalValue=values(SignalValue),ReportTime=values(ReportTime)
 </insert>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值