日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

SpringBoot +MyBatis批量插入數據

作者:Wen先森 更新時間: 2024-03-21 編程語言

?? 背景介紹

在最近的開發過程中,遇到了往數據庫中表中插入大量的數據。有一個全國銀行各分行的信息,共計148032條數據
文件有8.45MB,因為考慮到數據量比較大,就想著導入到MySQL看一看需要多長時間。

?? 方案一:用 for語句循環插入(不推薦)

使用for循環語句將,將數據一條條插入。

insert into t_bank values (?, ?, ?, ?, ?)
 /**
     * 導入銀行信息
     *
     * @param bankList
     * @return java.lang.String
     */
    @Override
    public String importBank(List<TBank> bankList) {
        if (StringUtils.isNull(bankList) || bankList.size() == 0)
        {
            throw new CustomException("導入用戶數據不能為空!");
        }
        long start = System.currentTimeMillis();
        for (int i = 0; i < bankList.size(); i++) {
            tBankMapper.insertTBank(bankList.get(i));
        }
        long end = System.currentTimeMillis();
        log.info("數據總耗時:" + (end-start) + "ms" );
        return "Success";
    }

優勢:JDBC 中的 PreparedStatement 有預編譯功能,預編譯之后會緩存起來。
之后SQL執行會比較快,且 JDBC可以開啟批處理,這個批處理執行非常給力。
劣勢:這種方式插入大量數據時,效率非常底下,不推薦。很多時候我們的 SQL 服務器和應用服務器可能并不是同一臺,所以必須要考慮網絡 IO。
如果網絡 IO 比較費時間的話,那么可能會拖慢 SQL 執行的速度。

?? 方案二:利用mybatis的foreach來實現循環插入(不推薦)

insert into t_bank values (?, ?, ?, ?, ?) , (?, ?, ?, ?, ?) , (?, ?, ?, ?, ?)
/**
     * 導入銀行信息
     *
     * @param bankList
     * @return java.lang.String
     */
    @Override
    public String importBank(List<TBank> bankList) {
        if (StringUtils.isNull(bankList) || bankList.size() == 0)
        {
            throw new CustomException("導入用戶數據不能為空!");
        }
        long start = System.currentTimeMillis();
        tBankMapper.batchInsert(bankList);
        long end = System.currentTimeMillis();
        log.info("數據總耗時:" + (end-start) + "ms" );
        return "Success";
    }
<insert id="batchInsert" parameterType="java.util.List">
        insert into t_bank (
                            bank_id,
                            branch_name,
                            bank_code,
                            contact_line,
                            parent_id,
                            branch_province,
                            branch_province_name,
                            branch_city,
                            branch_city_name)
        values
        <foreach collection="list" item="item" separator=",">
            (
                #{item.bankId},
                #{item.branchName},
                #{item.bankCode},
                #{item.contactLine},
                #{item.parentId},
                #{item.branchProvince},
                #{item.branchProvinceName},
                #{item.branchCity},
                #{item.branchCityName})
        </foreach>
    </insert>

優勢:不用頻繁訪問數據庫,一條sql搞定,效率比較高。

劣勢:一當數據量太大時,會出現拼接的sql語句超長而執行失敗,所以當數據量太大時,也不推薦。

二是 SQL 太長了,甚至可能需要分片后批量處理。

三是無法充分發揮 PreparedStatement 預編譯的優勢,SQL 要重新解析且無法復用

?? 第三種方案,使用sqlSessionFactory實現批量插入(推薦)

	@Resource
    private SqlSessionFactory sqlSessionFactory;
 /**
     * 導入銀行信息
     *
     * @param bankList
     * @param isUpdateSupport
     * @return java.lang.String
     * @author PuWenshuo
     * @date 2023/9/18 11:32
     */
    @Override
    public String importBank(List<TBank> bankList, Boolean isUpdateSupport) {
        if (StringUtils.isNull(bankList) || bankList.size() == 0)
        {
            throw new CustomException("導入用戶數據不能為空!");
        }
        String msg="";
        long start = System.currentTimeMillis();
        // 指定分頁大小
        int pageSize = 1000; // 每批插入1000條數據
        // 關閉session的自動提交
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
        try {
            TBankMapper bankMapper = sqlSession.getMapper(TBankMapper.class);
            // 計算總頁數
            int totalSize = bankList.size();
            int totalPages = (int) Math.ceil((double) totalSize / pageSize);
            for (int page = 1; page <= totalPages; page++) {
                // 計算當前頁的起始和結束索引
                int startIndex = (page - 1) * pageSize;
                int endIndex = Math.min(startIndex + pageSize, totalSize);

                // 獲取當前頁的數據
                List<TBank> banks = bankList.subList(startIndex, endIndex);
                // 批量插入數據
                tBankMapper.batchInsert(banks);
                // 提交事務
                sqlSession.commit();
            }
            msg="恭喜您,數據已全部導入成功!";
        } catch (Exception e) {
            sqlSession.rollback();
            log.error(e.getMessage());
            msg="很抱歉,導入失敗!";
        } finally {
            sqlSession.close();
        }
        long end = System.currentTimeMillis();
        log.info("數據總耗時:" + (end-start) + "ms" );
        return msg;
    }

優勢:這種方式可以說是集第一種和第二種方式的優點于一身,既可以提高運行效率,又可以保證大數據量時執行成功,大數據量時推薦使用這種方式。

原文鏈接:https://blog.csdn.net/qq_41596778/article/details/132990502

  • 上一篇:沒有了
  • 下一篇:沒有了
欄目分類
最近更新