數據庫批量插入上限問題


一、出現的問題

近期公司有個老項目(數據庫使用的  postgresql )需要維護需改,其中需要使用Excel 表格導入大批量的數據,因為excel導入數據存在太多不確定性,大量的數據校驗和數據的關聯查詢是避免不了的,這就會導致響應時間太久,這里為了優化采取了數據庫的批量插入,在小數據量時,批量插入還算正常,當數據量過大時就出現了以下的報錯;

報錯信息:Caused by: java.io.IOException: Tried to send an out-of-range integer as a 2-byte value: 120237

Caused by: java.io.IOException: Tried to send an out-of-range integer as a 2-byte value: 120237
    at org.postgresql.core.PGStream.sendInteger2(PGStream.java:211) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
    at org.postgresql.core.v3.QueryExecutorImpl.sendParse(QueryExecutorImpl.java:1409) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
    at org.postgresql.core.v3.QueryExecutorImpl.sendOneQuery(QueryExecutorImpl.java:1729) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
    at org.postgresql.core.v3.QueryExecutorImpl.sendQuery(QueryExecutorImpl.java:1294) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:280) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
    at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:430) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:356) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
    at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:168) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]
    at org.postgresql.jdbc.PgPreparedStatement.execute(PgPreparedStatement.java:157) ~[postgresql-9.4.1212.jre7.jar:9.4.1212.jre7]

問題出現原因:查了查 這是因為PostgreSQL數據庫jdbc driver對prepared Statement的參數 set的時候, client端的一個發送大小限制在2-byte。

 

二、解決方法(分批插入)

1、首先想到的是,用一個count值標識,記錄一下當list集合的size達到一定量進行批量插入一次,然后再把集合清空(使用list.clear())最后在循環外進行最后一次插入;這樣雖然可以解決但是代碼冗余太大而且不容易維護;

2、提取了一個公用類:

package com.**.**.framework.utils;

import org.apache.commons.collections.CollectionUtils;

import java.util.List;

/**
 * @author D-L
 * @Classname BatchHandlerUtil
 * @Version 1.0
 * @Description   分批處理list集合工具類
 * @Date 2020/7/30
 */
public class BatchHandlerUtil<T> {
    /**
     *  通過自定義分批參數      例如list.size() = 10000  ; batchSize = 1000  ; 分成10組進行resolve 操作
     * @param list 需要拆分的集合
     * @param batchSize 拆分大小
     * @param resolve do something you like ----------
     */
    public void  batchResolve(List<T> list, int batchSize, CommonResolve resolve) {
        //集合為空直接返回
        if(CollectionUtils.isEmpty(list)) return;
        for(int i = 0; i < list.size(); i += batchSize) {
            int end = i + batchSize;
            if(end > list.size()) {
                end = list.size();
            }
            List<T> items = list.subList(i, end);
            resolve.resolve(items);
        }
    }
}

函數式接口:java8新特性(@FunctionalInterface),提供一個處理業務邏輯的函數:

package com.**.**.framework.utils;

import java.util.List;

/**
 * @author D-L
 * @Classname CommonResolve
 * @Version 1.0
 * @Description   分批處理list集合 (因為數據庫批量插入有一定的限制)
 * @Date 2020/7/30
 */
@FunctionalInterface
public interface CommonResolve {
    void resolve(List items) ;
}

使用方法:

 if(dataSourceList.size() > 0){
            new BatchHandlerUtil<DischargeRegister>().batchResolve(dataSourceList, 1000, (item) -> {
                //do something you want...like you can deal your data to datasource
                dischargeRegisterMapper.insertByBatch(item);
            });
 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM