精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

300萬數(shù)據(jù)導(dǎo)入導(dǎo)出優(yōu)化方案,從80s優(yōu)化到8s(實測)

開發(fā) 項目管理
在項目開發(fā)中往往需要使用到數(shù)據(jù)的導(dǎo)入和導(dǎo)出,導(dǎo)入就是從Excel中導(dǎo)入到DB中,而導(dǎo)出就是從DB中查詢數(shù)據(jù)然后使用POI寫到Excel上。

前景

在項目開發(fā)中往往需要使用到數(shù)據(jù)的導(dǎo)入和導(dǎo)出,導(dǎo)入就是從Excel中導(dǎo)入到DB中,而導(dǎo)出就是從DB中查詢數(shù)據(jù)然后使用POI寫到Excel上。

寫本文的背景是因為在工作中遇到了大數(shù)據(jù)的導(dǎo)入和導(dǎo)出,問題既然來了逃跑不如干掉它!!!

只要這一次解決了,后期遇到同樣的問題就好解決了。

廢話不多說,開始擼起來!!!

1.傳統(tǒng)POI的的版點比較

其實想到數(shù)據(jù)的導(dǎo)入導(dǎo)出,理所當(dāng)然的會想到apache的poi技術(shù),以及Excel的版本問題。

既然要做導(dǎo)入導(dǎo)出,那么我們就先來大致看一下傳統(tǒng)poi技術(shù)的版本以及優(yōu)缺點對比吧!

首先我們知道POI中我們最熟悉的莫過于WorkBook這樣一個接口,我們的POI版本也在更新的同時對這個幾口的實現(xiàn)類做了更新:

  • HSSFWorkbook :

這個實現(xiàn)類是我們早期使用最多的對象,它可以操作Excel2003以前(包含2003)的所有Excel版本。在2003以前Excel的版本后綴還是.xls

  • XSSFWorkbook :

這個實現(xiàn)類現(xiàn)在在很多公司都可以發(fā)現(xiàn)還在使用,它是操作的Excel2003--Excel2007之間的版本,Excel的擴展名是.xlsx

  • SXSSFWorkbook :

這個實現(xiàn)類是POI3.8之后的版本才有的,它可以操作Excel2007以后的所有版本Excel,擴展名是.xlsx

大致知道了我們在導(dǎo)入導(dǎo)出操作的時候會用到這樣三個實現(xiàn)類以及他們可以操作的Excel版本和后綴之后,我們就要從優(yōu)缺點分析他們了

HSSFWorkbook

它是POI版本中最常用的方式,不過:

  • 它的缺點是 最多只能導(dǎo)出 65535行,也就是導(dǎo)出的數(shù)據(jù)函數(shù)超過這個數(shù)據(jù)就會報錯;
  • 它的優(yōu)點是 不會報內(nèi)存溢出。(因為數(shù)據(jù)量還不到7w所以內(nèi)存一般都夠用,首先你得明確知道這種方式是將數(shù)據(jù)先讀取到內(nèi)存中,然后再操作)

XSSFWorkbook

  • 優(yōu)點:這種形式的出現(xiàn)是為了突破HSSFWorkbook的65535行局限,是為了針對Excel2007版本的1048576行,16384列,最多可以導(dǎo)出104w條數(shù)據(jù);
  • 缺點:伴隨的問題來了,雖然導(dǎo)出數(shù)據(jù)行數(shù)增加了好多倍,但是隨之而來的內(nèi)存溢出問題也成了噩夢。因為你所創(chuàng)建的book,Sheet,row,cell等在寫入到Excel之前,都是存放在內(nèi)存中的(這還沒有算Excel的一些樣式格式等等),可想而知,內(nèi)存不溢出就有點不科學(xué)了!!!

SXSSFWorkbook

從POI 3.8版本開始,提供了一種基于XSSF的低內(nèi)存占用的SXSSF方式:

優(yōu)點:

  • 這種方式不會一般不會出現(xiàn)內(nèi)存溢出(它使用了硬盤來換取內(nèi)存空間,
  • 也就是當(dāng)內(nèi)存中數(shù)據(jù)達(dá)到一定程度這些數(shù)據(jù)會被持久化到硬盤中存儲起來,而內(nèi)存中存的都是最新的數(shù)據(jù)),
  • 并且支持大型Excel文件的創(chuàng)建(存儲百萬條數(shù)據(jù)綽綽有余)。

缺點:

  • 既然一部分?jǐn)?shù)據(jù)持久化到了硬盤中,且不能被查看和訪問那么就會導(dǎo)致,
  • 在同一時間點我們只能訪問一定數(shù)量的數(shù)據(jù),也就是內(nèi)存中存儲的數(shù)據(jù);
  • sheet.clone()方法將不再支持,還是因為持久化的原因;
  • 不再支持對公式的求值,還是因為持久化的原因,在硬盤中的數(shù)據(jù)沒法讀取到內(nèi)存中進行計算;
  • 在使用模板方式下載數(shù)據(jù)的時候,不能改動表頭,還是因為持久化的問題,寫到了硬盤里就不能改變了;

2.使用方式哪種看情況

經(jīng)過了解也知道了這三種Workbook的優(yōu)點和缺點,那么具體使用哪種方式還是需要看情況的:

我一般會根據(jù)這樣幾種情況做分析選擇:

  • 當(dāng)我們經(jīng)常導(dǎo)入導(dǎo)出的數(shù)據(jù)不超過7w的情況下,可以使用 HSSFWorkbook 或者 XSSFWorkbook都行;
  • 當(dāng)數(shù)據(jù)量查過7w并且導(dǎo)出的Excel中不牽扯對Excel的樣式,公式,格式等操作的情況下,推薦使用SXSSFWorkbook;
  • 當(dāng)數(shù)據(jù)量查過7w,并且我們需要操做Excel中的表頭,樣式,公式等,這時候我們可以使用 XSSFWorkbook 配合進行分批查詢,分批寫入Excel的方式來做;

3.百萬數(shù)據(jù)導(dǎo)入導(dǎo)出(正菜)

鋪墊也做了不少,那么現(xiàn)在開始講講我在工作中遇到的超百萬數(shù)據(jù)的導(dǎo)入導(dǎo)出解決方案:

想要解決問題我們首先要明白自己遇到的問題是什么?

我遇到的數(shù)據(jù)量超級大,使用傳統(tǒng)的POI方式來完成導(dǎo)入導(dǎo)出很明顯會內(nèi)存溢出,并且效率會非常低;

  • 數(shù)據(jù)量大直接使用select * from tableName肯定不行,一下子查出來300w條數(shù)據(jù)肯定會很慢;
  • 300w 數(shù)據(jù)導(dǎo)出到Excel時肯定不能都寫在一個Sheet中,這樣效率會非常低;估計打開都得幾分鐘;
  • 300w數(shù)據(jù)導(dǎo)出到Excel中肯定不能一行一行的導(dǎo)出到Excel中。頻繁IO操作絕對不行;
  • 導(dǎo)入時300萬數(shù)據(jù)存儲到DB如果循環(huán)一條條插入也肯定不行;
  • 導(dǎo)入時300w數(shù)據(jù)如果使用Mybatis的批量插入肯定不行,因為Mybatis的批量插入其實就是SQL的循環(huán);一樣很慢。

解決思路:

針對1 :

其實問題所在就是內(nèi)存溢出,我們只要使用對上面介紹的POI方式即可,主要問題就是原生的POI解決起來相當(dāng)麻煩。

經(jīng)過查閱資料翻看到阿里的一款POI封裝工具EasyExcel,上面問題等到解決;

針對2:

不能一次性查詢出全部數(shù)據(jù),我們可以分批進行查詢,只不過時多查詢幾次的問題,況且市面上分頁插件很多。此問題好解決。

針對3:

可以將300w條數(shù)據(jù)寫到不同的Sheet中,每一個Sheet寫一百萬即可。

針對4:

不能一行一行的寫入到Excel上,我們可以將分批查詢的數(shù)據(jù)分批寫入到Excel中。

針對5:

導(dǎo)入到DB時我們可以將Excel中讀取的數(shù)據(jù)存儲到集合中,到了一定數(shù)量,直接批量插入到DB中。

針對6:

不能使用Mybatis的批量插入,我們可以使用JDBC的批量插入,配合事務(wù)來完成批量插入到DB。即 Excel讀取分批+JDBC分批插入+事務(wù)。

3.1 EasyExcel 簡介

附上GitHub地址:https://github.com/alibaba/easyexcel

GitHub地址上教程和說明很詳細(xì),并且附帶有讀和寫的demo代碼,這里對它的介紹我就不再詳細(xì)說了。

至于EasyExcel底層怎么實現(xiàn)的這個還有待研究。

3.2 300w數(shù)據(jù)導(dǎo)出

EasyExcel完成300w數(shù)據(jù)的導(dǎo)出。技術(shù)難點已經(jīng)知道了,接下來就是針對這一難點提供自己的解決思路即可。

300w數(shù)據(jù)的導(dǎo)出解決思路:

  • 首先在查詢數(shù)據(jù)庫層面,需要分批進行查詢(我使用的是每次查詢20w)
  • 每查詢一次結(jié)束,就使用EasyExcel工具將這些數(shù)據(jù)寫入一次;
  • 當(dāng)一個Sheet寫滿了100w條數(shù)據(jù),開始將查詢的數(shù)據(jù)寫入到另一個Sheet中;
  • 如此循環(huán)直到數(shù)據(jù)全部導(dǎo)出到Excel完畢。

注意:

1)我們需要計算Sheet個數(shù),以及循環(huán)寫入次數(shù)。特別是最后一個Sheet的寫入次數(shù)

因為你不知道最后一個Sheet選喲寫入多少數(shù)據(jù),可能是100w,也可能是25w因為我們這里的300w只是模擬數(shù)據(jù),有可能導(dǎo)出的數(shù)據(jù)比300w多也可能少

2)我們需要計算寫入次數(shù),因為我們使用的分頁查詢,所以需要注意寫入的次數(shù)。

其實查詢數(shù)據(jù)庫多少次就是寫入多少次。

//導(dǎo)出邏輯代碼
public void dataExport300w(HttpServletResponse response) {
    {
        OutputStream outputStream = null;
        try {
            long startTime = System.currentTimeMillis();
            System.out.println("導(dǎo)出開始時間:" + startTime);

            outputStream = response.getOutputStream();
            ExcelWriter writer = new ExcelWriter(outputStream, ExcelTypeEnum.XLSX);
            String fileName = new String(("excel100w").getBytes(), "UTF-8");

            //title
            Table table = new Table(1);
            List<List<String>> titles = new ArrayList<List<String>>();
            titles.add(Arrays.asList("onlineseqid"));
            titles.add(Arrays.asList("businessid"));
            titles.add(Arrays.asList("becifno"));
            titles.add(Arrays.asList("ivisresult"));
            titles.add(Arrays.asList("createdby"));
            titles.add(Arrays.asList("createddate"));
            titles.add(Arrays.asList("updateby"));
            titles.add(Arrays.asList("updateddate"));
            titles.add(Arrays.asList("risklevel"));
            table.setHead(titles);

            //模擬統(tǒng)計查詢的數(shù)據(jù)數(shù)量這里模擬100w
            int count = 3000001;
            //記錄總數(shù):實際中需要根據(jù)查詢條件進行統(tǒng)計即可
            Integer totalCount = actResultLogMapper.findActResultLogByCondations(count);
            //每一個Sheet存放100w條數(shù)據(jù)
            Integer sheetDataRows = ExcelConstants.PER_SHEET_ROW_COUNT;
            //每次寫入的數(shù)據(jù)量20w
            Integer writeDataRows = ExcelConstants.PER_WRITE_ROW_COUNT;
            //計算需要的Sheet數(shù)量
            Integer sheetNum = totalCount % sheetDataRows == 0 ? (totalCount / sheetDataRows) : (totalCount / sheetDataRows + 1);
            //計算一般情況下每一個Sheet需要寫入的次數(shù)(一般情況不包含最后一個sheet,因為最后一個sheet不確定會寫入多少條數(shù)據(jù))
            Integer oneSheetWriteCount = sheetDataRows / writeDataRows;
            //計算最后一個sheet需要寫入的次數(shù)
            Integer lastSheetWriteCount = totalCount % sheetDataRows == 0 ? oneSheetWriteCount : (totalCount % sheetDataRows % writeDataRows == 0 ? (totalCount / sheetDataRows / writeDataRows) : (totalCount / sheetDataRows / writeDataRows + 1));

            //開始分批查詢分次寫入
            //注意這次的循環(huán)就需要進行嵌套循環(huán)了,外層循環(huán)是Sheet數(shù)目,內(nèi)層循環(huán)是寫入次數(shù)
            List<List<String>> dataList = new ArrayList<>();
            for (int i = 0; i < sheetNum; i++) {
                //創(chuàng)建Sheet
                Sheet sheet = new Sheet(i, 0);
                sheet.setSheetName("測試Sheet1" + i);
                //循環(huán)寫入次數(shù): j的自增條件是當(dāng)不是最后一個Sheet的時候?qū)懭氪螖?shù)為正常的每個Sheet寫入的次數(shù),如果是最后一個就需要使用計算的次數(shù)lastSheetWriteCount
                for (int j = 0; j < (i != sheetNum - 1 ? oneSheetWriteCount : lastSheetWriteCount); j++) {
                    //集合復(fù)用,便于GC清理
                    dataList.clear();
                    //分頁查詢一次20w
                    PageHelper.startPage(j + 1 + oneSheetWriteCount * i, writeDataRows);
                    List<ActResultLog> reslultList = actResultLogMapper.findByPage100w();
                    if (!CollectionUtils.isEmpty(reslultList)) {
                        reslultList.forEach(item -> {
                            dataList.add(Arrays.asList(item.getOnlineseqid(), item.getBusinessid(), item.getBecifno(), item.getIvisresult(), item.getCreatedby(), Calendar.getInstance().getTime().toString(), item.getUpdateby(), Calendar.getInstance().getTime().toString(), item.getRisklevel()));
                        });
                    }
                    //寫數(shù)據(jù)
                    writer.write0(dataList, sheet, table);
                }
            }

            // 下載EXCEL
            response.setHeader("Content-Disposition", "attachment;filename=" + new String((fileName).getBytes("gb2312"), "ISO-8859-1") + ".xlsx");
            response.setContentType("multipart/form-data");
            response.setCharacterEncoding("utf-8");
            writer.finish();
            outputStream.flush();
            //導(dǎo)出時間結(jié)束
            long endTime = System.currentTimeMillis();
            System.out.println("導(dǎo)出結(jié)束時間:" + endTime + "ms");
            System.out.println("導(dǎo)出所用時間:" + (endTime - startTime) / 1000 + "秒");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
3.2.1 測試機狀態(tài)

下面是測試機配置:

圖片圖片

圖片圖片

圖片圖片

圖片圖片

3.2.2 使用數(shù)據(jù)庫版本

數(shù)據(jù)庫我使用的是Oracle19C在網(wǎng)上查閱其實在數(shù)據(jù)量不超過1億的情況下,Mysql和Oracle的性能其實相差不大,超過1億,Oracle的各方面優(yōu)勢才會明顯。

所以這里可以忽略使用數(shù)據(jù)庫對時間造成的影響,使用mysql一樣可以完成測試,不需要單獨安裝Oracle。

這次測試在查詢方面我使用的是rownum進行的模擬查詢300w條數(shù)據(jù),這種查詢效率其實并不高,實際還有很多優(yōu)化空間來加快查詢速度,

如:明確查詢具體字段,不要用星號,經(jīng)常查詢字段增加索引等盡可能提高查詢效率,用時可能會更短。

<select id="findByPage300w" resultType="show.mrkay.pojo.ActResultLog">
    select *
    from ACT_RESULT_LOG
    where rownum <![CDATA[<]]> 3000001
</select>
-- 建表語句:可以參考一下
-- Create table
create table ACT_RESULT_LOG
(
  onlineseqid VARCHAR2(32),
  businessid  VARCHAR2(32),
  becifno     VARCHAR2(32),
  ivisresult  VARCHAR2(32),
  createdby   VARCHAR2(32),
  createddate DATE,
  updateby    VARCHAR2(32),
  updateddate DATE,
  risklevel   VARCHAR2(32)
)
tablespace STUDY_KAY
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );
3.2.3 測試結(jié)果

下面是300w數(shù)據(jù)從DB導(dǎo)出到Excel所用時間

從上面結(jié)果可以看出,300w的數(shù)據(jù)導(dǎo)出時間用時2分15秒,并且這是在不適用實體作為映射的情況下,如果使用實體映射不適用循環(huán)封裝的話速度會更快(當(dāng)然這也是在沒有設(shè)置表頭等其他表格樣式的情況下)

綜合來說速度還算可以。

在網(wǎng)上查了很多資料有一個博主測試使用EasyExcel導(dǎo)出102w數(shù)據(jù)用時105秒,具體可以看一下鏈接:

https://blog.csdn.net/u014299266/article/details/107790561

看一下導(dǎo)出效果:文件還是挺大的163M

圖片圖片

圖片圖片

3.2.4 導(dǎo)出小結(jié)

經(jīng)過測試EasyExcel還是挺快的,并且使用起來相當(dāng)方便,作者還專門提供了關(guān)流方法,不需要我們手動去關(guān)流了,也避免了我們經(jīng)常忘記關(guān)流導(dǎo)致的一系列問題。

導(dǎo)出測試就到這里,對于數(shù)據(jù)量小于300W的數(shù)據(jù)可以使用在一個Sheet中進行導(dǎo)出。這里就不再演示。

3.3 300w數(shù)據(jù)導(dǎo)入

代碼不重要首先還是思路

300W數(shù)據(jù)的導(dǎo)入解決思路

1)首先是分批讀取讀取Excel中的300w數(shù)據(jù),這一點EasyExcel有自己的解決方案,我們可以參考Demo即可,只需要把它分批的參數(shù)3000調(diào)大即可。我是用的20w;(一會兒代碼一看就能明白)

2)其次就是往DB里插入,怎么去插入這20w條數(shù)據(jù),當(dāng)然不能一條一條的循環(huán),應(yīng)該批量插入這20w條數(shù)據(jù),同樣也不能使用Mybatis的批量插入語,因為效率也低。可以參考下面鏈接【Myabtis批量插入和JDBC批量插入性能對比】

3)使用JDBC+事務(wù)的批量操作將數(shù)據(jù)插入到數(shù)據(jù)庫。(分批讀取+JDBC分批插入+手動事務(wù)控制)

https://www.cnblogs.com/wxw7blog/p/8706797.html

3.3.1 數(shù)據(jù)庫數(shù)據(jù)(導(dǎo)入前)

如圖:

圖片

3.3.2 核心業(yè)務(wù)代碼
// EasyExcel的讀取Excel數(shù)據(jù)的API
@Test
public void import2DBFromExcel10wTest() {
    String fileName = "D:\\StudyWorkspace\\JavaWorkspace\\java_project_workspace\\idea_projects\\SpringBootProjects\\easyexcel\\exportFile\\excel300w.xlsx";
    //記錄開始讀取Excel時間,也是導(dǎo)入程序開始時間
    long startReadTime = System.currentTimeMillis();
    System.out.println("------開始讀取Excel的Sheet時間(包括導(dǎo)入數(shù)據(jù)過程):" + startReadTime + "ms------");
    //讀取所有Sheet的數(shù)據(jù).每次讀完一個Sheet就會調(diào)用這個方法
    EasyExcel.read(fileName, new EasyExceGeneralDatalListener(actResultLogService2)).doReadAll();
    long endReadTime = System.currentTimeMillis();
    System.out.println("------結(jié)束讀取Excel的Sheet時間(包括導(dǎo)入數(shù)據(jù)過程):" + endReadTime + "ms------");
}
// 事件監(jiān)聽
public class EasyExceGeneralDatalListener extends AnalysisEventListener<Map<Integer, String>> {
    /**
     * 處理業(yè)務(wù)邏輯的Service,也可以是Mapper
     */
    private ActResultLogService2 actResultLogService2;

    /**
     * 用于存儲讀取的數(shù)據(jù)
     */
    private List<Map<Integer, String>> dataList = new ArrayList<Map<Integer, String>>();

    public EasyExceGeneralDatalListener() {
    }
    
    public EasyExceGeneralDatalListener(ActResultLogService2 actResultLogService2) {
        this.actResultLogService2 = actResultLogService2;
    }
    
    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        //數(shù)據(jù)add進入集合
        dataList.add(data);
        //size是否為100000條:這里其實就是分批.當(dāng)數(shù)據(jù)等于10w的時候執(zhí)行一次插入
        if (dataList.size() >= ExcelConstants.GENERAL_ONCE_SAVE_TO_DB_ROWS) {
            //存入數(shù)據(jù)庫:數(shù)據(jù)小于1w條使用Mybatis的批量插入即可;
            saveData();
            //清理集合便于GC回收
            dataList.clear();
        }
    }

    /**
     * 保存數(shù)據(jù)到DB
     *
     * @param
     * @MethodName: saveData
     * @return: void
     */
    private void saveData() {
        actResultLogService2.import2DBFromExcel10w(dataList);
        dataList.clear();
    }
    
    /**
     * Excel中所有數(shù)據(jù)解析完畢會調(diào)用此方法
     *
     * @param: context
     * @MethodName: doAfterAllAnalysed
     * @return: void
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData();
        dataList.clear();
    }
}
//JDBC工具類
public class JDBCDruidUtils {
    private static DataSource dataSource;

    /*
   創(chuàng)建數(shù)據(jù)Properties集合對象加載加載配置文件
    */
    static {
        Properties pro = new Properties();
        //加載數(shù)據(jù)庫連接池對象
        try {
            //獲取數(shù)據(jù)庫連接池對象
            pro.load(JDBCDruidUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
            dataSource = DruidDataSourceFactory.createDataSource(pro);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
    獲取連接
     */
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }


    /**
     * 關(guān)閉conn,和 statement獨對象資源
     *
     * @param connection
     * @param statement
     * @MethodName: close
     * @return: void
     */
    public static void close(Connection connection, Statement statement) {
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 關(guān)閉 conn , statement 和resultset三個對象資源
     *
     * @param connection
     * @param statement
     * @param resultSet
     * @MethodName: close
     * @return: void
     */
    public static void close(Connection connection, Statement statement, ResultSet resultSet) {
        close(connection, statement);
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /*
    獲取連接池對象
     */
    public static DataSource getDataSource() {
        return dataSource;
    }

}
# druid.properties配置
driverClassName=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:ORCL
username=mrkay
password=******
initialSize=10
maxActive=50
maxWait=60000
// Service中具體業(yè)務(wù)邏輯

/**
 * 測試用Excel導(dǎo)入超過10w條數(shù)據(jù),經(jīng)過測試發(fā)現(xiàn),使用Mybatis的批量插入速度非常慢,所以這里可以使用 數(shù)據(jù)分批+JDBC分批插入+事務(wù)來繼續(xù)插入速度會非常快
 *
 * @param
 * @MethodName: import2DBFromExcel10w
 * @return: java.util.Map<java.lang.String, java.lang.Object>
 */
@Override
public Map<String, Object> import2DBFromExcel10w(List<Map<Integer, String>> dataList) {
    HashMap<String, Object> result = new HashMap<>();
    //結(jié)果集中數(shù)據(jù)為0時,結(jié)束方法.進行下一次調(diào)用
    if (dataList.size() == 0) {
        result.put("empty", "0000");
        return result;
    }
    //JDBC分批插入+事務(wù)操作完成對10w數(shù)據(jù)的插入
    Connection conn = null;
    PreparedStatement ps = null;
    try {
        long startTime = System.currentTimeMillis();
        System.out.println(dataList.size() + "條,開始導(dǎo)入到數(shù)據(jù)庫時間:" + startTime + "ms");
        conn = JDBCDruidUtils.getConnection();
        //控制事務(wù):默認(rèn)不提交
        conn.setAutoCommit(false);
        String sql = "insert into ACT_RESULT_LOG (onlineseqid,businessid,becifno,ivisresult,createdby,createddate,updateby,updateddate,risklevel) values";
        sql += "(?,?,?,?,?,?,?,?,?)";
        ps = conn.prepareStatement(sql);
        //循環(huán)結(jié)果集:這里循環(huán)不支持"爛布袋"表達(dá)式
        for (int i = 0; i < dataList.size(); i++) {
            Map<Integer, String> item = dataList.get(i);
            ps.setString(1, item.get(0));
            ps.setString(2, item.get(1));
            ps.setString(3, item.get(2));
            ps.setString(4, item.get(3));
            ps.setString(5, item.get(4));
            ps.setTimestamp(6, new Timestamp(System.currentTimeMillis()));
            ps.setString(7, item.get(6));
            ps.setTimestamp(8, new Timestamp(System.currentTimeMillis()));
            ps.setString(9, item.get(8));
            //將一組參數(shù)添加到此 PreparedStatement 對象的批處理命令中。
            ps.addBatch();
        }
        //執(zhí)行批處理
        ps.executeBatch();
        //手動提交事務(wù)
        conn.commit();
        long endTime = System.currentTimeMillis();
        System.out.println(dataList.size() + "條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:" + endTime + "ms");
        System.out.println(dataList.size() + "條,導(dǎo)入用時:" + (endTime - startTime) + "ms");
        result.put("success", "1111");
    } catch (Exception e) {
        result.put("exception", "0000");
        e.printStackTrace();
    } finally {
        //關(guān)連接
        JDBCDruidUtils.close(conn, ps);
    }
    return result;
}
3.3.3 測試結(jié)果

下面是300w數(shù)據(jù)邊讀邊寫用時間:

大致計算一下:

從開始讀取到中間分批導(dǎo)入再到程序結(jié)束總共用時: (1623127964725-1623127873630)/1000=91.095秒

300w數(shù)據(jù)正好是分15次插入綜合用時:8209毫秒 也就是 8.209秒

計算可得300w數(shù)據(jù)讀取時間為:91.095-8.209=82.886秒

結(jié)果顯而易見:

EasyExcel分批讀取300W數(shù)據(jù)只用了 82.886秒

使用JDBC分批+事務(wù)操作插入300w條數(shù)據(jù)綜合只用時 8.209秒

------開始讀取Excel的Sheet時間(包括導(dǎo)入數(shù)據(jù)過程):1623127873630ms------
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127880632ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127881513ms
200000條,導(dǎo)入用時:881ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127886945ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127887429ms
200000條,導(dǎo)入用時:484ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127892894ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127893397ms
200000條,導(dǎo)入用時:503ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127898607ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127899066ms
200000條,導(dǎo)入用時:459ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127904379ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127904855ms
200000條,導(dǎo)入用時:476ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127910495ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127910939ms
200000條,導(dǎo)入用時:444ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127916271ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127916744ms
200000條,導(dǎo)入用時:473ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127922465ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127922947ms
200000條,導(dǎo)入用時:482ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127928260ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127928727ms
200000條,導(dǎo)入用時:467ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127934374ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127934891ms
200000條,導(dǎo)入用時:517ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127940189ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127940677ms
200000條,導(dǎo)入用時:488ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127946402ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127946925ms
200000條,導(dǎo)入用時:523ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127952158ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127952639ms
200000條,導(dǎo)入用時:481ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127957880ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127958925ms
200000條,導(dǎo)入用時:1045ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫時間:1623127964239ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫時間:1623127964725ms
200000條,導(dǎo)入用時:486ms
------結(jié)束讀取Excel的Sheet時間(包括導(dǎo)入數(shù)據(jù)過程):1623127964725ms------

看一下數(shù)據(jù)庫的數(shù)據(jù)是不是真的存進去了300w。

可以看到數(shù)據(jù)比導(dǎo)入前多了300W,測試很成功。

圖片

3.3.4 導(dǎo)入小結(jié)

具體我沒有看網(wǎng)上其他人的測試情況,這東西一般也很少有人愿意測試,不過這個速度對于我當(dāng)時解決公司大數(shù)據(jù)的導(dǎo)入和導(dǎo)出已經(jīng)足夠,當(dāng)然公司的業(yè)務(wù)邏輯很復(fù)雜,數(shù)據(jù)量也比較多,表的字段也比較多,導(dǎo)入和導(dǎo)出的速度會比現(xiàn)在測試的要慢一點,但是也在人類能接受的范圍之內(nèi)。

4.總結(jié)

這次工作中遇到的問題也給我留下了深刻印象,同時也是我職業(yè)生涯添彩的一筆。

最起碼簡歷上可以寫上你處理過上百萬條數(shù)據(jù)的導(dǎo)入導(dǎo)出。

最后說一下公司之前怎么做的,公司之前做法是

限制了用戶的下載數(shù)量每次最多只能有四個人同時下載,并且控制每個用戶最大的導(dǎo)出數(shù)據(jù)最多只能是20w,與此同時他們也是使用的JDBC分批導(dǎo)入,但是并沒有手動控制事務(wù)。

控制同時下載人數(shù)我可以理解,但是控制下載數(shù)據(jù)最多為20w就顯得有點雞肋了。

這也是我后期要解決的問題。

好了到此結(jié)束,相信大神有比我做的更好的,對于EasyExcel內(nèi)部到底是怎么實現(xiàn)的還有待考究(有空我再研究研究)。

責(zé)任編輯:武曉燕 來源: JAVA日知錄
相關(guān)推薦

2019-06-20 11:20:25

sql優(yōu)化數(shù)據(jù)庫

2025-11-11 04:00:00

2022-09-27 08:40:44

慢查詢MySQL定位優(yōu)化

2022-07-05 10:50:31

數(shù)據(jù)庫查詢實戰(zhàn)

2023-11-29 08:10:52

類型sql語句

2023-05-14 17:16:22

分類樹SpringBoot

2023-12-25 08:24:03

雙異步數(shù)據(jù)庫Excel

2024-09-29 08:21:06

2020-02-23 17:15:29

SQL分析查詢

2021-09-10 08:31:36

技術(shù)Prometheus監(jiān)控

2024-10-28 07:00:00

分頁查詢優(yōu)化索引數(shù)據(jù)歸檔

2025-06-25 09:30:14

2022-09-19 08:41:02

數(shù)據(jù)查詢分離

2023-09-27 08:21:00

查詢分離數(shù)據(jù)API

2024-05-28 08:47:52

2024-03-04 08:29:33

數(shù)據(jù)定制化Java

2022-06-30 19:40:36

查詢接口索引優(yōu)化

2024-08-30 09:31:36

2024-11-08 09:34:54

2025-06-27 09:05:47

點贊
收藏

51CTO技術(shù)棧公眾號

一区二区视频国产| 日本精品在线视频 | 给我看免费高清在线观看| 国产高清视频色在线www| 91麻豆文化传媒在线观看| 日本午夜人人精品| 小早川怜子一区二区的演员表| a一区二区三区亚洲| 亚洲伊人伊色伊影伊综合网| 精品蜜桃一区二区三区| 国产成人精品一区二区色戒| 欧美电影免费播放| 精品国产99国产精品| 欧美日韩中文在线视频| 麻豆传媒免费在线观看| 懂色av一区二区三区免费看| 45www国产精品网站| 久久免费手机视频| julia中文字幕一区二区99在线| 精品美女国产在线| 在线电影看在线一区二区三区| 成人久久久精品国产乱码一区二区| 亚洲一区二区三区免费在线观看| 色播久久人人爽人人爽人人片视av| 精品人妻一区二区乱码| 久久电影tv| 亚洲激情综合网| 欧美日韩精品免费观看| av网站在线观看免费| 久久人人超碰| 欧美黑人狂野猛交老妇| 免费黄在线观看| 91成人入口| 欧美日韩精品福利| 成人av一级片| 欧洲在线视频| 国产精品女同互慰在线看| 成人资源视频网站免费| 中文字幕欧美人妻精品| 国产日本精品| 久精品免费视频| 黄色免费一级视频| 欧美日韩123| 亚洲成人激情在线| 女王人厕视频2ⅴk| 日本一区二区三区中文字幕| 色久优优欧美色久优优| 人妻少妇精品无码专区二区| 老司机在线永久免费观看| 久久蜜桃香蕉精品一区二区三区| www.成人av.com| 国产精品乱码一区二区| 日韩精品免费视频人成| 欧美在线视频免费| 男人的天堂一区二区| 亚洲图片欧美日韩| 超碰成人免费| 91精品国产91热久久久做人人| 黄色一级大片在线观看| 日本在线影院| 天天操天天色综合| 青青草国产精品视频| 黄网站在线观| 亚洲一区精品在线| av一区二区三区免费观看| 黄页视频在线播放| 亚洲人精品午夜| 亚洲一区二区四区| 毛片免费不卡| 亚洲丝袜另类动漫二区| 超碰成人在线免费观看| 麻豆系列在线观看| 日韩毛片视频在线看| 亚洲第一综合网站| 欧美hdxxx| 亚洲一本大道在线| 欧洲精品一区二区三区久久| 2018av在线| 精品久久久一区| 国产1区2区在线| 台湾佬成人网| 欧美日韩国产一级片| 手机免费看av网站| 欧美精品影院| 亚洲国产免费av| 三叶草欧洲码在线| 欧美一区二区三| 久久精品亚洲94久久精品| 日韩欧美国产成人精品免费| 欧美一区综合| 国自产精品手机在线观看视频| 日韩精品视频免费看| 亚洲一区日韩在线| 国产精品扒开腿做爽爽爽视频| 在线免费观看一区二区| 韩国欧美国产1区| 国产精品9999久久久久仙踪林| 天堂网av2014| 国产欧美视频一区二区| 一区二区91美女张开腿让人桶| 老司机精品影院| 午夜精品久久久久久| 亚洲视频在线观看一区二区三区| 欧美视频第一| 欧美成人vr18sexvr| 亚洲午夜久久久久久久久红桃| 成人免费a**址| 欧美大片在线看免费观看| 欧美亚洲精品天堂| 激情久久久久久久久久久久久久久久| 国产精品久久久久久久免费大片 | 久久99亚洲网美利坚合众国| 狠狠躁夜夜躁人人躁婷婷91 | 欧美日韩亚洲综合在线 | 欧美成人综合| 欧美亚洲第一页| 国产一区二区三区成人| av高清不卡在线| 亚洲欧美电影在线观看| av资源中文在线| 欧美日韩视频在线观看一区二区三区 | 91在线播放视频| 男人天堂资源在线| 亚洲一级二级三级| 亚洲精品永久视频| 婷婷综合一区| 九九久久久久久久久激情| 波多野结衣电影在线播放| 国产aⅴ综合色| 亚洲国产精品一区二区第四页av| 欧美精品videosex| 欧美精品丝袜中出| 亚洲妇女无套内射精| 成人免费电影网址| 欧洲精品久久久| 亚洲av综合色区无码一二三区| 欧美精彩视频一区二区三区| r级无码视频在线观看| 成人在线分类| 中文字幕亚洲一区| 波多野结衣在线电影| 99久久免费精品高清特色大片| 黑人巨茎大战欧美白妇| 四虎国产精品免费久久| 国产一区二区三区直播精品电影| 日本在线小视频| 国产伦精品一区二区三区在线观看 | 不卡的av影片| 日韩午夜av一区| 青青操在线视频观看| 全国精品久久少妇| 日韩电影大全在线观看| 一级毛片久久久| 日韩毛片在线看| 日韩免费视频网站| 成人av手机在线观看| 国产精品igao激情视频| 久久久久毛片免费观看| 久久夜色精品国产| 国产精品热久久| 亚洲欧美一区二区三区极速播放| 亚洲国产成人va在线观看麻豆| 国产在线日韩精品| 国产精品对白刺激| 成年人在线看| 欧美日韩国产综合久久| 中国一级片在线观看| 激情国产一区二区| 一级特黄妇女高潮| 视频二区欧美| 久久久久久中文| 色窝窝无码一区二区三区成人网站| 亚洲图片欧美视频| 亚洲一区二区三区无码久久| 亚洲一区区二区| 日本一区二区在线视频| 久久天堂影院| 久久天天躁狠狠躁夜夜爽蜜月| 国产美女永久免费| 一区二区三区不卡在线观看| jjzzjjzz欧美69巨大| 日韩一级在线| 欧美一二三区| 亚洲成人1区| 久久91精品国产91久久久| 性生活三级视频| 图片区小说区区亚洲影院| 99久久国产精| 久久精品国产一区二区三| 久久视频免费在线| 女仆av观看一区| 国产精品1234| 超碰在线观看免费| 亚洲精品电影在线观看| 91porny九色| 亚洲视频在线一区| av黄色一级片| 免费视频最近日韩| 欧美久久久久久久久久久久久久| 欧美精品中文字幕亚洲专区| 国产精品精品久久久| 91在线中字| 亚洲美女精品成人在线视频| 在线播放亚洲精品| 婷婷成人综合网| 少妇高潮惨叫久久久久| 国产成人av一区二区三区在线| 亚洲中文字幕无码中文字| 99热在线成人| 精品国产乱码久久久久| 巨大黑人极品videos精品| 欧美黑人性猛交| av在线免费一区| 精品国产91九色蝌蚪| 亚洲午夜无码久久久久| 亚洲成人中文在线| 2014亚洲天堂| www国产成人免费观看视频 深夜成人网| 色乱码一区二区三区在线| 日韩一级精品| 久久视频免费在线| 日本大胆欧美| 九九九九九九精品| 国产欧美88| 国产成人91久久精品| 黑人另类精品××××性爽| 日韩中文有码在线视频| 日本人妖在线| 精品久久久三级丝袜| 国产精品久久久久久久久久久久久久久久 | 成人免费av资源| 亚洲欧美国产中文| 日韩电影在线一区二区| 亚洲熟妇国产熟妇肥婆| 欧美精品啪啪| eeuss中文| 不卡av一区二区| 欧美高清一区二区| 牛牛视频精品一区二区不卡| 粉嫩av免费一区二区三区| 四虎在线精品| 国产精品嫩草影院一区二区| 中文不卡1区2区3区| 性金发美女69hd大尺寸| 日韩三级电影视频| 久久av红桃一区二区小说| 在线观看免费黄色| 国产一区二区三区网站| 国际av在线| 亚洲欧美制服丝袜| 欧美日韩在线中文字幕| 亚洲精品久久久久久下一站| 隣の若妻さん波多野结衣| 日韩精品一区二区三区在线| 国产又色又爽又黄又免费| 欧美日韩一二区| 国产又粗又猛又黄| 在线播放中文一区| 国产chinasex对白videos麻豆| 91麻豆精品国产91久久久久久久久| 中文字幕一级片| 欧美在线观看视频在线| 精品乱码一区内射人妻无码| 欧美午夜宅男影院| 国产一区二区三区黄片| 欧美一区二区三区日韩| 精品国产亚洲av麻豆| 欧美va亚洲va| 国产综合在线播放| 日韩av在线影院| 欧美大片aaa| 中文字幕日韩欧美在线视频| 91精品国产91久久久久游泳池| 中文字幕亚洲一区二区三区| 麻豆传媒视频在线| 欧美精品成人91久久久久久久| 成人女同在线观看| 2018日韩中文字幕| av激情成人网| 国产精品一久久香蕉国产线看观看| 国产综合色激情| 91久久久久久久久久| 日韩在线成人| 国产在线精品一区二区三区》 | 欧美一区二区福利| 日韩免费视频| 成年在线观看视频| 在线视频亚洲| 蜜臀av免费观看| 国产一区二区在线视频| 97人妻精品一区二区三区免费 | 欧美日韩四区| 国产中文字幕在线免费观看| 日韩av电影天堂| 中文字幕第三区| 91视频www| 国产精品酒店视频| 午夜私人影院久久久久| 久久久精品毛片| 91精品国产91综合久久蜜臀| 五十路在线观看| www.xxxx精品| caoporn视频在线观看| 国产精品入口免费视频一| 亚洲成人五区| 日韩免费毛片| 尤物在线精品| 日日干夜夜操s8| a在线播放不卡| 五月婷婷综合激情网| 欧美日韩亚洲系列| 国产草草影院ccyycom| 亚洲免费精彩视频| 日本性爱视频在线观看| 国产精品免费视频xxxx| 超碰精品在线| 艳母动漫在线免费观看| 老司机精品福利视频| 日本wwwwwww| 国产精品免费久久| 欧美h在线观看| 精品精品欲导航| 欧美边添边摸边做边爱免费| 国产成人av在线播放| 动漫3d精品一区二区三区乱码| 亚洲午夜在线观看| 久久精品人人做人人爽电影蜜月| 俄罗斯女人裸体性做爰| 国产精品国产精品国产专区不片| 日本特级黄色片| 欧美va亚洲va香蕉在线| 国产成人l区| 国产精品成人va在线观看| 亚洲国产合集| 国产免费黄色一级片| 韩国毛片一区二区三区| 日本高清黄色片| 色域天天综合网| 天天综合网在线观看| 久久久久久国产免费| 欧美特黄不卡| 路边理发店露脸熟妇泻火| 免费黄网站欧美| 国产伦理片在线观看| 日本福利一区二区| 蜜桃视频在线观看视频| 欧洲亚洲女同hd| 亚洲欧洲av| 国语对白做受xxxxx在线中国| 97精品久久久久中文字幕| 日本午夜小视频| 精品999在线播放| 国产盗摄在线视频网站| 国产精品亚洲一区| 亚洲人妖在线| 亚洲综合自拍网| 午夜电影网亚洲视频| 日韩中文字幕影院| 久久久久亚洲精品成人网小说| 一区中文字幕电影| 日本阿v视频在线观看| 成人免费视频免费观看| 久久久精品视频免费| 欧美精品一区二区精品网| 波多一区二区| 久久久精品动漫| 久久天堂成人| 亚洲第一成人网站| 日本韩国一区二区三区视频| av片在线免费观看| 国产欧美日韩视频| 91成人精品视频| 美女流白浆视频| 亚洲国产视频网站| 天堂网www中文在线| 青青精品视频播放| 日韩精品水蜜桃| 亚洲综合20p| 亚洲午夜电影网| 日韩精品一二| 国产精品久久二区| 一区二区三区午夜视频| 亚洲婷婷在线观看| 色婷婷激情综合| 日本电影全部在线观看网站视频| 亚洲自拍小视频免费观看| 亚洲国产精品一区制服丝袜| 三级网站在线免费观看| 欧美日韩成人综合在线一区二区| www.在线视频| 国产区一区二区| 日韩国产欧美视频| 色婷婷在线视频观看| 精品偷拍一区二区三区在线看| 91精品国产66| 国产成人永久免费视频| 久久久精品天堂| 国产高潮流白浆喷水视频| 欧美一级成年大片在线观看| 国产精品99视频|