com.mysql.jdbc.PacketTooBigException: Packet for query is too large (8346602 > 4194304). You can change this value on the server by setting the max_allowed_packet’ variable. ——mysql sql大小超过4M时执行失败
现需求对mysql批量新增数据,mybatis的foreach标签是拼接成一条sql然后执行批量插入,如果数据量超过mysql的默认4M就会报上面的错误;对此,可以将一条长sql拆分为多个sql,保证小于4M,或者修改my.cnf扩大4M限制。
1.定义拆分工具类import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import java.util.List;
public class SplitListUtils {
public static List> split(List resList, int subListLength) {
if (CollectionUtils.isEmpty(resList) || subListLength <= 0) {
return Lists.newArrayList();
}
List> ret = Lists.newArrayList();
int size = resList.size();
if (size <= subListLength) {
// 数据量不足 subListLength 指定的大小
ret.add(resList);
} else {
int pre = size / subListLength;
int last = size % subListLength;
// 前面pre个集合,每个大小都是 subListLength 个元素
for (int i = 0; i < pre; i++) {
List itemList = Lists.newArrayList();
for (int j = 0; j < subListLength; j++) {
itemList.add(resList.get(i * subListLength + j));
}
ret.add(itemList);
}
// last的进行处理
if (last > 0) {
List itemList = Lists.newArrayList();
for (int i = 0; i < last; i++) {
itemList.add(resList.get(pre * subListLength + i));
}
ret.add(itemList);
}
}
return ret;
}
// 运行代码
public static void main(String[] args) {
List list = Lists.newArrayList();
int size = 1099;
for (int i = 0; i < size; i++) {
list.add("hello-" + i);
}
// 大集合里面包含多个小集合
List> temps = split(list, 100);
int j = 0;
// 对大集合里面的每一个小集合进行操作
for (List obj : temps) {
System.out.println(String.format("row:%s -> size:%s,data:%s", ++j, obj.size(), obj));
}
}
}
2.多线程批量新增
public void threadInsertMysql(ListtotalList) { // 初始化线程池, 参数一定要一定要一定要调好!!!! ThreadPoolExecutor threadPool = new ThreadPoolExecutor(20, 50, 4, TimeUnit.SECONDS, new ArrayBlockingQueue(10), new ThreadPoolExecutor.AbortPolicy()); // 大集合拆分成N个小集合, 这里集合的size可以稍微小一些(这里我用100刚刚好), 以保证多线程异步执行, 过大容易回到单线程 List splitNList = SplitListUtils.split(totalList, 100); // 记录单个任务的执行次数 CountDownLatch countDownLatch = new CountDownLatch(splitNList.size()); // 对拆分的集合进行批量处理, 先拆分的集合, 再多线程执行 for (List singleList : splitNList) { // 线程池执行 threadPool.execute(new Thread(new Runnable(){ @Override public void run() { // 批量新增操作 if(!CollectionUtils.isEmpty(singleList)){ batchInsertorUpdateEntity(singleList); } // 任务个数 - 1, 直至为0时唤醒await() countDownLatch.countDown(); } })); } // 让当前线程处于阻塞状态,直到锁存器计数为零 countDownLatch.await(); }



