编程日记 批量导入数据

编程日记 批量导入数据

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对象都完成。

posted @   vast_joy  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示