欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用Java實(shí)現(xiàn)百萬(wàn)Excel數(shù)據(jù)導(dǎo)出

 更新時(shí)間:2024年03月07日 09:54:33   作者:夢(mèng)塵啊  
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)百萬(wàn)Excel數(shù)據(jù)導(dǎo)出,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考一下

可能出現(xiàn)的問題

  • 同步導(dǎo)數(shù)據(jù),接口很容易超時(shí)。
  • 如果把所有數(shù)據(jù)一次性裝載到內(nèi)存,很容易引起OOM。
  • 數(shù)據(jù)量太大sql語(yǔ)句慢。
  • 如果走異步,如何通知用戶導(dǎo)出結(jié)果
  • 如果excel文件太大,目標(biāo)用戶打不開怎么辦

解決方案

問題一 異步化 調(diào)用接口立即返回任務(wù)生產(chǎn)成功

問題二 分批查詢 poi 禁止使用XSSFWorkbook 使用SXSSFWorkbook 或 easy Excel

問題三 分頁(yè)通過滾動(dòng)翻頁(yè)查詢

流式查詢問題:容易長(zhǎng)時(shí)間占用數(shù)據(jù)庫(kù)鏈接池資源。

游標(biāo)查詢問題:應(yīng)用指定每次查詢獲取的條數(shù)fetchSize,MySQL服務(wù)器每次只查詢指定條數(shù)的數(shù)據(jù),由于MySQL方不知道客戶端什么時(shí)候?qū)?shù)據(jù)消費(fèi)完,MySQL需要建立一個(gè)臨時(shí)空間來存放每次查詢出的數(shù)據(jù),大數(shù)據(jù)量時(shí)MySQL服務(wù)器、磁盤占用都會(huì)飆升。

故使用滾動(dòng)翻頁(yè)查詢

問題四 通過 頁(yè)面或者溝通軟件通知用戶導(dǎo)出成功 ,并將導(dǎo)出結(jié)果上傳至oss 后續(xù)可直接下載 無需重復(fù)導(dǎo)出

問題五 導(dǎo)出可用戶設(shè)置最大條數(shù)

數(shù)據(jù)準(zhǔn)備

CREATE TABLE `t_order`
(
    `id`           BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '主鍵',
    `creator`      VARCHAR(16)     NOT NULL DEFAULT 'admin' COMMENT '創(chuàng)建人',
    `editor`       VARCHAR(16)     NOT NULL DEFAULT 'admin' COMMENT '修改人',
    `create_time`  DATETIME        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
    `edit_time`    DATETIME        NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時(shí)間',
    `version`      BIGINT          NOT NULL DEFAULT 1 COMMENT '版本號(hào)',
    `deleted`      TINYINT         NOT NULL DEFAULT 0 COMMENT '軟刪除標(biāo)識(shí)',
    `order_id`     VARCHAR(32)     NOT NULL COMMENT '訂單ID',
    `amount`       DECIMAL(10, 2)  NOT NULL DEFAULT 0 COMMENT '訂單金額',
    `payment_time` DATETIME        NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT '支付時(shí)間',
    `order_status` TINYINT         NOT NULL DEFAULT 0 COMMENT '訂單狀態(tài),0:處理中,1:支付成功,2:支付失敗',
    UNIQUE uniq_order_id (`order_id`),
    INDEX idx_payment_time (`payment_time`)
) COMMENT '訂單表';
public class OrderServiceTest {
    private static final Random OR = new Random();
    private static final Random AR = new Random();
    private static final Random DR = new Random();
    @Test
    public void testGenerateTestOrderSql() throws Exception {
        HikariConfig config = new HikariConfig();
        config.setUsername("root");
        config.setPassword("root");
        config.setJdbcUrl("jdbc:mysql://localhost:3306/local?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false");
        config.setDriverClassName("com.mysql.jdbc.Driver");
        HikariDataSource hikariDataSource = new HikariDataSource(config);
        JdbcTemplate jdbcTemplate = new JdbcTemplate(hikariDataSource);
        for (int d = 0; d < 100; d++) {
            String item = "('%s','%d','2020-07-%d 00:00:00','%d')";
            StringBuilder sql = new StringBuilder("INSERT INTO t_order(order_id,amount,payment_time,order_status) VALUES ");
            for (int i = 0; i < 20_000; i++) {
                sql.append(String.format(item, UUID.randomUUID().toString().replace("-", ""),
                        AR.nextInt(100000) + 1, DR.nextInt(31) + 1, OR.nextInt(3))).append(",");
            }
            jdbcTemplate.update(sql.substring(0, sql.lastIndexOf(",")));
        }
        hikariDataSource.close();
    }
}

具體實(shí)現(xiàn)

easy Excel通過滾動(dòng)翻頁(yè)

Controller

@GetMapping(path = "/export")
public void export(@RequestParam(name = "paymentDateStart") String paymentDateStart,
                   @RequestParam(name = "paymentDateEnd") String paymentDateEnd,
                   ) throws Exception {
    orderService.export(paymentDateStart, paymentDateEnd);
}

Service

@Async
public void export(String paymentDateStart, String paymentDateEnd) throws IOException {
    Date dateBefore = new Date();
    String fileName = URLEncoder.encode(String.format("%s-(%s).xlsx", "訂單數(shù)據(jù)", UUID.randomUUID()),
            StandardCharsets.UTF_8.toString());
    BufferedOutputStream outputStream = FileUtil.getOutputStream(FileUtil.file("/Users/Documents/github/"+fileName));

    ExcelWriter writer = new ExcelWriterBuilder()
            .autoCloseStream(true)
            .excelType(ExcelTypeEnum.XLSX)
            .file(outputStream)
            .head(OrderDTO.class)
            .build();
    WriteSheet writeSheet = new WriteSheet();
    writeSheet.setSheetName("target");
    long lastBatchMaxId = 0L;
    int limit = 3000;
    for (; ; ) {
        List<OrderDTO> list = queryByScrollingPagination(paymentDateTimeStart, paymentDateTimeEnd, lastBatchMaxId, limit);
      //可以添加導(dǎo)出條數(shù)限制
        if (list.isEmpty()) {
            writer.finish();
            Date dateAfter = new Date();
            System.out.println("導(dǎo)出列表共執(zhí)行" + (dateAfter.getTime() - dateBefore.getTime()) + "ms");
            //todo 上傳oss 發(fā)通知
            break;
        } else {
            lastBatchMaxId = list.stream().map(OrderDTO::getId).max(Long::compareTo).orElse(Long.MAX_VALUE);
            writer.write(list, writeSheet);
        }
    }
}
public List<OrderDTO> queryByScrollingPagination(String paymentDateTimeStart,
                                                 String paymentDateTimeEnd,
                                                 long lastBatchMaxId,
                                                 int limit) {
    LocalDateTime start = LocalDateTime.parse(paymentDateTimeStart, formatter);
    LocalDateTime end = LocalDateTime.parse(paymentDateTimeEnd, formatter);
    return orderDao.queryByScrollingPagination(lastBatchMaxId, limit, start, end).stream().map(order -> {
        OrderDTO dto = new OrderDTO();
        dto.setId(order.getId());
        dto.setAmount(order.getAmount());
        dto.setOrderId(order.getOrderId());
        dto.setCreator(order.getCreator());
        return dto;
    }).collect(Collectors.toList());
}

Repository

@Repository
public class OrderDao {

    @Resource
    private  JdbcTemplate jdbcTemplate;

    public List<Order> queryByScrollingPagination(long lastBatchMaxId,
                                                  int limit,
                                                  LocalDateTime paymentDateTimeStart,
                                                  LocalDateTime paymentDateTimeEnd) {
        return jdbcTemplate.query("SELECT id,creator,editor ,version,deleted,order_id,amount,order_status FROM t_order WHERE id > ? AND payment_time >= ? AND payment_time <= ? " +
                        "ORDER BY id ASC LIMIT ?",
                p -> {
                    p.setLong(1, lastBatchMaxId);
                    p.setTimestamp(2, Timestamp.valueOf(paymentDateTimeStart));
                    p.setTimestamp(3, Timestamp.valueOf(paymentDateTimeEnd));
                    p.setInt(4, limit);
                },
                rs -> {
                    List<Order> orders = new ArrayList<>();
                    while (rs.next()) {
                        Order order = new Order();
                        order.setId(rs.getLong("id"));
                        order.setCreator(rs.getString("creator"));
                        order.setEditor(rs.getString("editor"));
                           order.setVersion(rs.getLong("version"));
                        order.setDeleted(rs.getInt("deleted"));
                        order.setOrderId(rs.getString("order_id"));
                        order.setAmount(rs.getBigDecimal("amount"));
                       order.setOrderStatus(rs.getInt("order_status"));
                        orders.add(order);
                    }
                    return orders;
                });
    }
}

總結(jié)

業(yè)務(wù)方面

做需求時(shí)刻先考慮是不是必須要做 、如果必須要做的情況需要考慮用戶的體驗(yàn)和使用感受

技術(shù)方面

1 不需要立馬返回結(jié)果的接口可以采用異步的方式讓接口立刻返回結(jié)果,可以防止接口耗時(shí)過長(zhǎng)導(dǎo)致tomcat線程池打滿。

2 MySQL批量查詢、數(shù)據(jù)同步、數(shù)據(jù)導(dǎo)出可以使用類似于分頁(yè)查詢的思路,但是鑒于LIMIT offset,size的效率太低,可以采用”滾動(dòng)翻頁(yè)”的實(shí)現(xiàn)方式 注意要用自增趨勢(shì)的主鍵

3 數(shù)據(jù)導(dǎo)出需要注意由于大對(duì)象頻繁創(chuàng)建導(dǎo)致的 full gc 和oom 如果導(dǎo)出較頻繁可以考慮拆分單獨(dú)服務(wù)專門做導(dǎo)出

到此這篇關(guān)于使用Java實(shí)現(xiàn)百萬(wàn)Excel數(shù)據(jù)導(dǎo)出的文章就介紹到這了,更多相關(guān)Java數(shù)據(jù)導(dǎo)出內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java老矣 尚能飯否?

    Java老矣 尚能飯否?

    Java老矣,尚能飯否?各類編程語(yǔ)言橫空出世,紛戰(zhàn)不休,然而 TIOBE 的語(yǔ)言排行榜上,Java 卻露出了明顯的頹勢(shì)。這個(gè)老牌的語(yǔ)言,未來會(huì)是怎樣?
    2017-06-06
  • Java開發(fā)中常用的 Websocket 技術(shù)參考

    Java開發(fā)中常用的 Websocket 技術(shù)參考

    WebSocket 使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡(jiǎn)單,允許服務(wù)端主動(dòng)向客戶端推送數(shù)據(jù),當(dāng)然也支持客戶端發(fā)送數(shù)據(jù)到服務(wù)端。
    2020-09-09
  • 淺談Android開發(fā)中項(xiàng)目的文件結(jié)構(gòu)及規(guī)范化部署建議

    淺談Android開發(fā)中項(xiàng)目的文件結(jié)構(gòu)及規(guī)范化部署建議

    這篇文章主要介紹了Android開發(fā)中項(xiàng)目的文件結(jié)構(gòu)及規(guī)范化部署建議,組織好代碼文件的結(jié)構(gòu)有利于維護(hù)團(tuán)隊(duì)合作的效率,需要的朋友可以參考下
    2016-03-03
  • 從log4j切換到logback后項(xiàng)目無法啟動(dòng)的問題及解決方法

    從log4j切換到logback后項(xiàng)目無法啟動(dòng)的問題及解決方法

    這篇文章主要介紹了從log4j切換到logback后項(xiàng)目無法啟動(dòng)的問題及解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-01-01
  • 盤點(diǎn)MQ中的異常測(cè)試

    盤點(diǎn)MQ中的異常測(cè)試

    這篇文章主要為大家介紹了盤點(diǎn)MQ中的異常測(cè)試,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • 異常解決SpringBoot項(xiàng)目啟動(dòng)卡住,無任何異常信息問題

    異常解決SpringBoot項(xiàng)目啟動(dòng)卡住,無任何異常信息問題

    這篇文章主要介紹了異常解決SpringBoot項(xiàng)目啟動(dòng)卡住,無任何異常信息問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • SpringCloud Gateway路由組件詳解

    SpringCloud Gateway路由組件詳解

    SpringCloud Gateway 是 Spring Cloud 的一個(gè)全新項(xiàng)目,它旨在為微服務(wù)架構(gòu)提供一種簡(jiǎn)單有效的統(tǒng)一的 API 路由管理方式。這篇文章主要介紹了SpringCloud Gateway網(wǎng)關(guān)作用,需要的朋友可以參考下
    2023-02-02
  • Java如何對(duì)返回參數(shù)進(jìn)行處理

    Java如何對(duì)返回參數(shù)進(jìn)行處理

    這篇文章主要介紹了Java如何對(duì)返回參數(shù)進(jìn)行處理問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • SpringCloud+Tornado基于jwt實(shí)現(xiàn)請(qǐng)求安全校驗(yàn)功能

    SpringCloud+Tornado基于jwt實(shí)現(xiàn)請(qǐng)求安全校驗(yàn)功能

    這篇文章主要介紹了SpringCloud+Tornado基于jwt實(shí)現(xiàn)請(qǐng)求安全校驗(yàn),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • Java Web項(xiàng)目部署在Tomcat運(yùn)行出錯(cuò)與解決方法示例

    Java Web項(xiàng)目部署在Tomcat運(yùn)行出錯(cuò)與解決方法示例

    這篇文章主要介紹了Java Web項(xiàng)目部署在Tomcat運(yùn)行出錯(cuò)與解決方法,結(jié)合具體實(shí)例形式分析了Java Web項(xiàng)目部署在Tomcat過程中由于xml配置文件導(dǎo)致的錯(cuò)誤問題常見提示與解決方法,需要的朋友可以參考下
    2017-03-03

最新評(píng)論