赞
踩
Mybatis后台批量插入数据报错:
数据库我用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方法:原创 | 为什么阿里巴巴要求谨慎使用ArrayList中的subList方法 - 好文 - 码工具
第二种方法:(推荐)
说到数组的操作我们肯定会想起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);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。