编程日记 批量导入数据
编程日记 批量导入数据
1.用可视化界面:适合一次性导入,数据量可控
2.写程序:for循环,建议分批,不要一把梭哈(可以用接口控制),要保证可控、幂等,注意线上环境和测试环境是有区别的
导入1000w条,for i 1000w
(不能再main方法里面写,会报空指针异常,userMapper无法注入)
缺点是.class并不是一个spring的bean,他没有被spring托管,无法使用@resounces注解
3.执行SQL语句,适用于小数据量
编写一次性任务
for循环插入数据的问题:
1.建立和释放数据库链接(批量查询解决)
@Resource
private UserService userService;
/**
* 批量插入用户
*/
@Test
//fixedDelay就是每隔5s执行一次
public void doInsertUsers() {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
final int INSERT_NUM = 100000;
List<User> userList = new ArrayList<>();
for (int i = 0; i < INSERT_NUM; i++) {
User user = new User();
user.setUsername("原_创 【鱼_皮】https://t.zsxq.com/0emozsIJh");
user.setUserAccount("fakeyupi");
user.setAvatarUrl("https://636f-codenav-8grj8px727565176-1256524210.tcb.qcloud.la/img/logo.png");
user.setGender(0);
user.setUserPassword("12345678");
user.setPhone("123");
user.setEmail("123@qq.com");
user.setTags("[]");
user.setUserStatus(0);
user.setUserRole(0);
user.setPlanetCode("11111111");
userList.add(user);
}
// 20 秒 10 万条
userService.saveBatch(userList, 1000);
stopWatch.stop();
System.out.println(stopWatch.getTotalTimeMillis());
}
2.for循环是绝对线性的(并发)
并发要注意执行的先后顺序无所谓
@Resource
private UserService userService;
/**
* 并发批量插入用户
*/
@Test
public void doConcurrencyInsertUsers() {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 分十组
int batchSize = 5000;
int j = 0;
List<CompletableFuture<Void>> futureList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
List<User> userList = new ArrayList<>();
while (true) {
j++;
User user = new User();
user.setUsername("假鱼皮");
user.setUserAccount("fakeyupi");
user.setAvatarUrl("https://636f-codenav-8grj8px727565176-1256524210.tcb.qcloud.la/img/logo.png");
user.setGender(0);
user.setUserPassword("12345678");
user.setPhone("123");
user.setEmail("123@qq.com");
user.setTags("[]");
user.setUserStatus(0);
user.setUserRole(0);
user.setPlanetCode("11111111");
userList.add(user);
if (j % batchSize == 0) {
break;
}
}
// 异步执行
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("threadName: " + Thread.currentThread().getName());
userService.saveBatch(userList, batchSize);
}, executorService);
futureList.add(future);
}
CompletableFuture.allOf(futureList.toArray(new CompletableFuture[]{})).join();
// 20 秒 10 万条
stopWatch.stop();
System.out.println(stopWatch.getTotalTimeMillis());
}
注意第38行代码:
这段代码是使用Java的CompletableFuture类来等待一组CompletableFuture对象全部执行完毕。
CompletableFuture.allOf(...)
,是一个静态方法,它接收一个CompletableFuture数组作为参数,并返回一个新的CompletableFuture对象。这个新的CompletableFuture对象会在参数中所有的CompletableFuture对象都执行完毕之后完成,即它会等待传入的所有CompletableFuture对象完成,才会执行下一条语句。
array.toArray(new CompletableFuture[]{})
,这段代码是将一个List集合(array)转换成一个数组,并作为参数传递给CompletableFuture.allOf()
方法。这是通过将List集合转换为一个空的CompletableFuture数组来实现的。
.join()
,是CompletableFuture对象的一个方法,会阻塞当前线程,直到该CompletableFuture对象完成,并返回对象的结果值。
此代码CompletableFuture.allOf(array.toArray(new CompletableFuture[]{})).join()
的意思是等待List集合(array)中的所有CompletableFuture对象都执行完毕,并阻塞当前线程直到所有CompletableFuture对象都完成。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构