mybatis批量insert报错原因分析

最近在项目中需要使用mybatis的批量插入功能,但是不知道为什么出现奇怪的错误,调试了很久,最终解决。
我的最初的mybatis批量插入语句如下:

	<insert id="insertDfldBatch" useGeneratedKeys="true" keyProperty="id">
   	    insert into dfld_new4 (way,sjdwz,ejdwz,stime,etime,sgcount,sgrate,distance,interval) values
  		<foreach item="item" collection="list" separator=",">
    		(#{item.way}, #{item.sjdwz}, #{item.ejdwz}, #{item.stime}, #{item.etime}, #{item.sgcount}, #{item.sgrate},#{item.distance},#{item.interval})
  		foreach>
	insert>

Java中的调用如下:

List<SegProne> data = new ArrayList<>();	//保存多发路段
...
ScanDao sd = new ScanDao();
sd.saveDfldBatch(data);
	//批量存储多发路段
	public void saveDfldBatch(List<SegProne> data, String lm) {
		SqlSession session = MyBatisUtil.getSqlSession();
		ScanMapper sm = session.getMapper(ScanMapper.class);
		if(data.size() > 0) {	//有的道路没有多发路段
			sm.insertDfldBatch(data);
		}
		session.commit();
		session.close();
	}

上述代码中data为需要存储的数据,由多个SegProne实体对象组成,通过调用saveDfldBatch方法保存。但是保存时出现如下错误:

网上搜索了一堆,最开始以为时插入的sql语句过长,于是删掉了interval,莫名奇妙居然好了,后来才发现原来interval是mysql中的关键字,sql语句中包含其关键字会报上述错误,好吧,居然是这个问题,当时完全没有考虑到。

当时还遇到的一个错误是mybatis一次性批量插入几万条记录可能会报错,因为mysql对语句的长度有限制,默认是 4M。遇到这种情况可以分批次进行插入,即将数据分成几个小批次,然后对每个小批次批量insert。
这里参考网上的封装一个对List数据分批的工具类:

package com.vcc.utils;

import java.util.ArrayList;
import java.util.List;

public class ListGrouper{

    /**
     * 将集合按指定数量分组
     * @param list 数据集合
     * @param quantity 分组数量
     * @return 分组结果
     */
    public static <T> List<List<T>> groupListByQuantity(List<T> list, int quantity) {
        if (list == null || list.size() == 0) {
            return null;
        }
        
        if (quantity <= 0) {
            new IllegalArgumentException("Wrong quantity.");
        }
        
        List<List<T>> wrapList = new ArrayList<List<T>>();
        int count = 0;
        while (count < list.size()) {
            wrapList.add(new ArrayList<T>(list.subList(count, (count + quantity) > list.size() ? list.size() : count + quantity)));
            count += quantity;
        }
        
        return wrapList;
    }
    
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        for (int i = 1; i <= 1011; i++) {
            list.add(i);
        }
        
        List<List<Integer>> resultList = ListGrouper.groupListByQuantity(list, 50);
        for (List<Integer> l : resultList) {
            System.out.println(l);
        }
        System.out.println(resultList.size());
    }
    
}

使用上述工具类对带插入数据分批处理,相应代码如下:

List<SegProne> data = new ArrayList<>();	//保存多发路段
...
ScanDao sd = new ScanDao();
//分批处理(mybatis批量插入长度有限制)
List<List<SegProne>> resultList = ListGrouper.groupListByQuantity(data, 1000);
System.out.println("分批: " + resultList.size());
for(List<SegProne> li: resultList) {
	sd.saveDfldBatch(li);
}

上述以1000条记录为一个批次进行插入。

参考:
(1)https://my.oschina.net/zjllovecode/blog/1818716
(2)https://blog.csdn.net/hdg745979749/article/details/77921085

你可能感兴趣的:(项目记录,Java,Web,MySQL)