JDBC连接池去做批量导入,每次运行500万数据,但是在中间就会出各种问题

自己写了一个JDBC连接池去做批量导入,每次运行500万数据,但是在中间就会出各种问题

问题1:The last packet successfully received from the server was 18,967 milliseconds ago. The last packet sent successfully to the server was 18,963 milliseconds ago.
对于问题一 这个时间默认是8小时,我刚起项目,运行不到30分钟,怎么会连接过期呢?网上说的去改哪个out时间,我也改过无效?单是看这个时间觉得也不是网上说的那样?
问题2:截了个图可以看图片

img


问题3:也是提交的时候报的错误;

代码也贴上了,每次报错都是提交的时候报的错误,ps.executeBatch();;


```java
    private void saveForecastSales(List<ForecastSalesDO> forecastSalesDOS, int count) {
        try {
            if (count > 2) {
                log.info("JDBCOperationServiceImpl->saveForecastSales:: 尝试两次无果");
                return;
            }
            Connection connection = dbPool.getConnection();
            if (!connection.isValid(1000)){
                dbPool.removeConnection(connection);
                log.error("JDBCOperationServiceImpl->saveForecastSales::connection ");
                connection = DbUtil.createConnection();
            }
            PreparedStatement  ps = connection.prepareStatement(JDBCUtils.SQL);
            connection.setAutoCommit(false);
            forecastSalesDOS.forEach(e -> {
                try {
                    ps.setObject(1, e.getSku());
                    ps.setObject(2, e.getErpSku());
                    ps.setObject(3, e.getSite());
                    ps.setObject(4, e.getMarketId());
                    ps.setObject(5, DateUtil.getMinusHours(e.getPaidTime()));
                    ps.setObject(6, e.getAmount());
                    ps.setObject(7, e.getPlatformId());
                    ps.setObject(8, e.getOrderType());
                    ps.setObject(9, e.getOrderCategory());
                    ps.setObject(10, e.getAsin());
                    ps.setObject(11, e.getIdealWarehouse());
                    ps.setObject(12, e.getActualFreight());
                    ps.setObject(13, e.getActualWarehouse());
                    ps.setObject(14, e.getCountry());
                    ps.setObject(15, e.getSimulatedNetProfit());
                    ps.setObject(16, e.getOrderTotalPrice());
                    ps.setObject(17, e.getOrderCode());
                    ps.setObject(18, e.getOrderCurrency());
                    ps.setObject(19, DateUtil.getMinusHours(e.getOrderCreatedTime()));
                    ps.setObject(20, e.getOrderSn());
                    ps.setObject(21, e.getFreight());
                    ps.setObject(22, e.getUnitPrice());
                    ps.setObject(23, e.getIsFba());
                    ps.setObject(24, DateUtil.getMinusHours(e.getCreatedTime()));
                    ps.setObject(25, e.getCreatedBy());
                    ps.setObject(26, DateUtil.getMinusHours(e.getUpdatedTime()));
                    ps.setObject(27, e.getUpdatedBy());
                    ps.setObject(28, e.getIsDelete());
                    ps.addBatch();
//                    ps.clearParameters();
                } catch (SQLException throwables) {
                    log.info("内层:JDBCOperationServiceImpl->batchForecastSales:异常,{}", throwables.getMessage());
                    throw new RuntimeException(throwables);
                }
            });
            DbUtil.executeBatchInsert(connection, ps);
            dbPool.releaseConnection(connection);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            log.info("外层:JDBCOperationServiceImpl->batchForecastSales:异常,SQLException::{}", throwables.getMessage());
            count++;
            log.info("尝试中:::::");
            this.saveForecastSales(forecastSalesDOS, count);
        }
    }

public static void executeBatchInsert(Connection connection, PreparedStatement ps) throws SQLException {
   if(ps==null){
       log.info("executeBatchInsert->为空");
   }
    ps.executeBatch();
    connection.commit();
    ps.clearBatch();
    closePs(ps);
}

```

一个能打的都没有吗?

500万都在forecastSalesDOS这个属性里?如果是的话那这些问题都可能是一个问题:数据库连接超时,connect属性可能已经超时了,导致问题2空指针异常,问题一明显是超时问题了,建议:
1.如果批量一次是500万insert的话建议少量多次循环批量且加事务,避免超时
2.在executeBatch前再向之前connect判断一下是不是还可用或者null这种情况

产生的原因:应用方的数据库连接有效期时间,大于数据库自己设置的有效期。
解决方案:

一、修改druid配置(如果使用druid的话)

1

2

3

4

spring.datasource.druid.validationQuery=select 1

spring.datasource.druid.testWhileIdle=true

spring.datasource.druid.testOnBorrow=true

spring.datasource.druid.testOnReturn=true

PS.此方案对性能会有一定影响

二、修改数据库连接配置

在数据库连接上,加“&autoReconnect=true&failOverReadOnly=false”配置

三、修改数据库连接有效时间

在数据库配置上设置,把数据库连接有效时间设置长一点,比如设置12小时或者24小时

四、还可以参考这篇文章的其它方法:https://www.cnblogs.com/jpfss/p/7206912.html

第一个问题应该是数据库连接超时了,一般连接可能就1分钟左右,网上搜索设置数据库连接超时时间的解决方案,第二个是ps创建对象没成功,你直接手动创建一个,第三个是不是一次性提交的数据太多了,sql过长也会报错,建议分批次提交,每次100条,然后用多线程调用,速度也不会慢