导出任务耗时如何优化

大量数据的导入导出时,请求一定非常耗时,页面一定会不停转圈圈,不可能让用户一直停留在这个页面转圈圈,这样并不友好。

比较好的方式就事通过异步的方式,先提交任务,然后通过线程的处理数据。一次性如果导出大量数据时,需要批量查询结果到处。

导出功能设计:

前端页面设计如下:
新增 导出按钮 和导出记录按钮
导出记录页面字段如下:
批次号 时间 导出URL 操作(导出)
后端表结构

create table export_record(
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
 `batch_no` varchar(32)  DEFAULT NULL COMMENT '导入批次号',
 `export_type` varchar(3) DEFAULT NULL COMMENT '类型(1:订单导出)',
  `export_url` varchar(300) DEFAULT NULL COMMENT 'url',
 `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
  `create_code` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人代码',
  `create_name` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人名称',
  `last_update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
  `last_update_code` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最后更新人',
  `last_update_name` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最后更新人',
   PRIMARY KEY (`id`),
   KEY `index_import_record` (`batch_no`) USING BTREE
)ENGINE=InnoDB  COMMENT='导出记录';

后端功能逻辑:
将导出的数据生成excel文件,并上传到服务器中,上传的文件生产的url保存记录,供前端页面下载excel文件

导入功能设计

前端页面设计如下:
image.png
导入记录页面字段如下:
批次号 时间 总条数 成功条数 操作
image.png

create table import_record (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
 `batch_no` varchar(32)  DEFAULT NULL COMMENT '导入批次号',
 `export_type` varchar(3) DEFAULT NULL COMMENT '类型(1:订单导出)',
  `total_num` int DEFAULT 0 COMMENT '总数量',
  `success_num` int DEFAULT 0 COMMENT '成功数量',
 `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
  `create_code` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人代码',
  `create_name` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人名称',
  `last_update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
  `last_update_code` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最后更新人',
  `last_update_name` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最后更新人',
   PRIMARY KEY (`id`),
   KEY `index_import_record` (`batch_no`) USING BTREE
)ENGINE=InnoDB  COMMENT='导入记录';


create table import_record (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
 `batch_no` varchar(32)  DEFAULT NULL COMMENT '导入批次号',
 `export_type` varchar(3) DEFAULT NULL COMMENT '类型(1:订单导出)',
  `total_num` int DEFAULT 0 COMMENT '总数量',
  `success_num` int DEFAULT 0 COMMENT '成功数量',
 `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
  `create_code` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人代码',
  `create_name` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人名称',
  `last_update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
  `last_update_code` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最后更新人',
  `last_update_name` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最后更新人',
   PRIMARY KEY (`id`),
   KEY `index_import_record` (`batch_no`) USING BTREE
)ENGINE=InnoDB  COMMENT='导入记录';

导入逻辑:
对导入的excel文件进行解析,并保存解析出来的数据。

大量数据查询拆分成批量任务查询

导出数据可能会导出大量数据,通常情况下,一次性查询大量数据导致负载压力的原因是在一次查询中同时检索了太多数据,并在内存中进行处理,这会占用大量系统资源,造成系统响应变慢和崩溃等问题。

mysql会将检索出来的数据都缓存到内存,一次性返回到服务端,这样会占用大量的内存资源,导致内存不足,从而影响系统运行稳定性。

解决的方式是批次处理,如分页查询数据,从而减少mysql查询占用的内存。
image.png

分页查询工具如下:

@CustomLog
public class PageBigDataUtil {

    /**
     * @param queryParam 查询条件
     * @param function 分页查询
     * @return
     */
    public static <T> List<T> pageBigData(T queryParam, Function<PageQueryBean<T>, PageQueryBean<T>> function) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        List<T> results = new ArrayList<>();
        int size = 500;
        int current = 1;
        for (; ; ) {
            PageQueryBean<T> pageParam = new PageQueryBean<>();
            SimplePage<T> simplePage = new SimplePage<>();
            simplePage.setPageSize(size);
            simplePage.setPageNum(current);
            pageParam.setPage(simplePage);
            pageParam.setParameter(queryParam);
            PageQueryBean<T> result = function.apply(pageParam);
            logger.keyword("分页批次任务").info("--------导入开始,本批次共:{} 轮,当前第{}轮", result.getPage().getPages(), current);
            if (DataUtil.isEmpty(result)) {
                break;
            }
            results.addAll(result.getPage().getList());
            if ((long) size * current >= result.getPage().getTotal()) {
                break;
            }
            current++;
        }
        stopWatch.stop();
        logger.info("批次任务已结束,分页批次任务:{},获取总记录数:{},总耗时:{}秒", current, results.size(), stopWatch.getTotalTimeSeconds());
        return results;
    }

    /**
     *
     * @param queryParam 查询条件
     * @param function 分页查询
     * @param consumer 批次消费
     * @param <T>
     */
    public static <T> void handleBigData(T queryParam, Function<PageQueryBean<T>, PageQueryBean<T>> function, Consumer<List<T>> consumer) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        int size = 500;
        int current = 1;
        for (; ; ) {
            PageQueryBean<T> pageParam = new PageQueryBean<>();
            SimplePage<T> simplePage = new SimplePage<>();
            simplePage.setPageSize(size);
            simplePage.setPageNum(current);
            pageParam.setPage(simplePage);
            pageParam.setParameter(queryParam);
            PageQueryBean<T> result = function.apply(pageParam);
            if (DataUtil.isEmpty(result)) {
                break;
            }
            // 业务处理
            consumer.accept(result.getPage().getList());
            logger.keyword("分页批次任务").info("--------导入开始,本批次共:{} 轮,当前第{}轮", result.getPage().getPages(), current);
            if ((long) size * current >= result.getPage().getTotal()) {
                break;
            }
            current++;
        }
        stopWatch.stop();
        logger.info("批次任务已结束,总耗时:{}秒", stopWatch.getTotalTimeSeconds());
    }
}

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我可以帮你编写一个Java的完整Controller,实现多线程导出Excel的功能。以下是一个示例代码: ```java import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @RestController public class ExcelExportController { private final ExecutorService executorService = Executors.newFixedThreadPool(5); // 创建一个固定线程池 @GetMapping("/export") public void exportExcel(HttpServletResponse response) { // 异步执行导出任务 executorService.execute(() -> { try { // 模拟耗时操作 Thread.sleep(3000); // 导出Excel的逻辑 // ... // 设置响应头 response.setHeader("Content-Disposition", "attachment; filename=\"export.xlsx\""); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); // 输出Excel内容到响应流 // ... response.flushBuffer(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } }); } } ``` 上述代码中,我们使用Spring Boot框架创建了一个RestController,其中包含了一个GET请求的导出Excel接口`/export`。在该接口中,我们通过`executorService`定义了一个固定线程池,然后使用`execute`方法提交一个导出任务。 在导出任务中,我们首先模拟了一个耗时操作,然后执行实际的Excel导出逻辑。最后,设置响应头和内容类型,并将Excel内容输出到响应流中,实现文件的下载。 请注意,上述代码只是一个示例,并没有完整的Excel导出逻辑和输出内容的实现,你需要根据自己的需求进行相应的开发。 希望能对你有帮助!如果还有其他问题,请随提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值