假设表字段 id(自增),标题,图片地址,视频地址,热度,创建时间,更新时间
如何高效的使用java向mysql插入1-10W条数据
我目前是 查询出数据遍历集合,一条一条的插入表中,一开始插入1W条的时候每秒大概能插入几百上千条,现在表中有30W条数据,再次插入1W条数据的时候每秒只能插入几条数据,插入1W条 大概用了30-40分钟,而且cpu直接爆表, 一开始服务器是8h16g的,后来升级到16h32g,再次插入还是出现同样的问题,不知道问题出在哪里
因为接口超时的原因,使用了多线程
你循环一条一条的插入,肯定会原来越慢,应该分批插入,比如一批1000条,1万条,就10批
注意我的问题,最好能解释 为什么cpu会爆,并贴出你的代码,谢谢
原因:
1.for循环中每次循环查询数据库;
2.插入数据为单条插入;
这样频繁操作数据库,所以会相当耗资源的。
建议:
1.可以把for循环中的查询提取出来,改为一次性查出所有,然后再去循环list
2.单条插入改成批量插入
3.可以使用多线程
下面代码仅供参考:
package com.hky;
import com.hky.service.AgentVideo;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import java.util.stream.Collectors;
/**
*
* @author hky
*/
public class Test {
private ForkJoinPool pool;
public Test() {
pool = new ForkJoinPool();
}
// 执行任务RecursiveTask:有返回值 RecursiveAction:无返回值
private static class SumTask extends RecursiveTask<Long> {
/**
*
*/
private static final long serialVersionUID = 1L;
private List<PublicDailiVideo> numbers;
private int from;
private int to;
public SumTask(List<PublicDailiVideo> numbers, int from, int to) {
this.numbers = numbers;
this.from = from;
this.to = to;
}
// 此方法为ForkJoin的核心方法:对任务进行拆分 拆分的好坏决定了效率的高低
@Override
protected Long compute() {
if (to - from < 1000) {
List<PublicDailiVideo> list = numbers.subList(from, to);
List<AgentVideo> agentVideoList = new ArrayList<>();
// 准备要批量插入的list
list.forEach(a -> {
AgentVideo agent = new AgentVideo();
agent.setName(a.getName());
agent.setImageUrl(a.getImageUrl());
agent.setVideoUrl(a.getVideoUrl());
agentVideoList.add(agent);
});
System.out.println("agentVideoList:" + agentVideoList.size());
// TODO 批量插入数据
System.out.println("批量插入数据:" + agentVideoList.size() + "条");
return (long) agentVideoList.size();
} else {
int middle = (from + to) / 2;
System.out.println("from:" + from + ",to:" + to + ",middle:" + middle);
SumTask task1 = new SumTask(numbers, from, middle);
SumTask task2 = new SumTask(numbers, middle, to);
task1.fork();
task2.fork();
return task1.join() + task2.join();
}
}
}
public long sumUp(List<PublicDailiVideo> numbers) {
Long res = pool.invoke(new SumTask(numbers, 0, numbers.size()));
System.out.println("线程池大小" + pool.getPoolSize());
pool.shutdown();
return res;
}
public static void main(String[] args) {
// 待循环的list
List<PublicDailiVideo> publicdiliList = new ArrayList<PublicDailiVideo>();
for (int i = 0; i < 10000; i++) {
PublicDailiVideo video = new PublicDailiVideo();
video.setName("ming" + i);
video.setImageUrl("imageUrl" + i);
video.setId(i + "");
video.setVideoUrl("videoUrl" + i);
publicdiliList.add(video);
}
System.out.println(publicdiliList.size());
// 下面对应你pulbicVideoMapper.selectPublicVideoById()
List<String> ids = publicdiliList.stream().map(PublicDailiVideo::getId).collect(Collectors.toList());
// TODO 然后根据ids查询 AgentVideo的list,
// 把查到的VideoUrl set到 publicdiliList 的中,这样就不需要你在for循环中,每循环一次就去查一次数据库了
Instant now = Instant.now();
Test calculator = new Test();
long result = calculator.sumUp(publicdiliList);
Instant end = Instant.now();
System.out.println("耗时:" + Duration.between(now, end).toMillis() + "ms");
System.out.println("结果为:" + result);
}
}
循环查的话太频繁,一直在与数据库进行交互,cpu再大都没用,建议用批量插入,java有这个功能