PostgreSQL的SQL语句参数上限 An I/O error occurred while sending to the backend

事故现场:

数据库我用postgreSQL,持久成框架mybatis
现在有一个操作,需要将一大批数据(3000+)插入数据库,后台直接报错,报错原因如下:

org.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.

Caused by: java.io.IOException: Tried to send an out-of-range integer as a 2-byte value: 50805

原因:批量插入的顶峰在JDBC-Driver出现天花板.
简单来说就是SQL语句参数上限

可能我们首先想到的解决办法是分段批量插入,将sql语句分成几次执行,比如现在有3500条数据,一次性最多插入1500,分为3次插入;那代码怎么实现呢?
下面介绍2种解决方法,2种方法都用了递归算法;(当时的情况我这边一次性可以插入1800条,具体要看数据表中有多少字段)

  • 注:以下方法可以写在service的通用方法中(如果有的话),这样所有实体类的service都可以调用

第一种方法:

这是我的第一次尝试,虽然不太灵活,但能用,记录一下;后来才有第二种方法;

直接用java.util.List包提供的方法subList(int fromIndex, int toIndex);
subList是List接口中定义的一个方法,该方法主要用于返回一个集合中的一段,可以理解为截取一个集合中的部分元素,他的返回值也是一个List。方法中的2个参数可以看成是数组的下标;代码如下:

/**
 * 递归插入
 * @author: fangzf
 * @param:  @param all     需要批量插入的集合
 * @param:  @param strart  开始的下标
 * @param:  @param end     结束的下标(包头不包尾)
*/
public void add (List<T> all,int strart, int end){

    if(all.size()<=end){
        end = all.size();
    }

    //截取strart ~ end条数据
    List<T> collect = all.subList(strart, end);
    if(CollUtil.isEmpty(collect)){
        return;
    }

     //批量插入数据的方法(这里是通用的批量插入数据方法)
    insertList(collect);
     //递归 每次插入1500条数据,这里1500写死了,就是不灵活的地方
     //可以再传一个参数过来,这样会比较灵活
    add(all,strart+1500,end+1500);
}

//调用批量插入的方法 all表示业务中要插入的数据数组
add(all,0,1500);

关于subList方法需要谨慎使用

在《阿里巴巴Java开发手册》中有提到subList方法需要谨慎使用,具体可以看一下这篇文章:
为什么阿里巴巴要求谨慎使用ArrayList中的subList方法:http://www.matools.com/blog/190706621

第二种方法:(推荐)

说到数组的操作我们肯定会想起java8提供强大的lambda表达式(链接到lambda表示文章),这里要用到skip和limit方法;

  • skip(n):跳过元素,返回一个扔掉前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。

  • limit(n):截断流,使其元素不超过给定数量。

代码如下:

//递归插入
public void add (List<Dormitory> all,long strart,long limit){
    //截取 从strart开始截取 截取limit条
	List<Dormitory> collect = all.stream().skip(strart).limit(limit).collect(Collectors.toList());
	if(CollUtil.isEmpty(collect)){
         return;
	}
      //批量插入数据的方法
	insertList(collect);
     //递归 每次插入limit条数据
	add(all,strart+limit,limit);
}

//调用批量插入的方法 all表示业务中要插入的数据数组
add(all,0L,1500L);

简单强大,推荐

发布了22 篇原创文章 · 获赞 6 · 访问量 507

猜你喜欢

转载自blog.csdn.net/qq_33732195/article/details/103898754