zoukankan      html  css  js  c++  java
  • 数据库批量插入上限问题

    一、出现的问题

    近期公司有个老项目(数据库使用的  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);
                });
     }
  • 相关阅读:
    如何消除一个数组里面重复的元素?
    行内元素有哪些?块级元素有哪些? 空(void)元素有那些?
    简述一下src与href的区别
    请说出三种减少页面加载时间的方法
    SQL大全
    11.Hibernate 拦截器
    10.Hibernate 批处理
    9.Hibernate 缓存
    8.Hibernate 原生 SQL
    7.Hibernate 标准查询
  • 原文地址:https://www.cnblogs.com/dongl961230/p/13403603.html
Copyright © 2011-2022 走看看