揭秘!Java我如何让42000毫秒数据处理时间大缩水,效率飙升6倍,直降至6000毫秒,速度新纪元

1.前几天我在给数据库批量添加数据,但是效率很慢,不能复用,于是乎写了一个方法,用于批量数据添加,代码为:获取用户传入的设备ID,查询该对象,并赋值,然后一条条添加;使用insert

方法(为什么不使用 “insertBatch”这个方法呢,测试过,很慢,需要52000ms,比一条条数据还慢),看了鱼皮的 数据恢复来了灵感,他使用了“CompletableFuture”这个类,来进行异步的处理;

我之前的代码为这样:


    public String createEquipmentDataBatch(String... equipmentCode) {
        Random random = new Random();
        String[] myArray = {"东风", "东南风", "南风", "北风", "东北风"};
        String[] myArray2 = {"金龟子", "蟋蟀", "蛾"};
        for (String equipmentid : equipmentCode) {
            //LinkedList<EquipmentDataDO> list = new LinkedList<>();
            //根据设备ID  查询 基地ID  地块ID 同时查询 设备分类名称 设备监测类型
            Map<String, Object> maps = equipmentDataMapper.selectEquInfo(equipmentid);
            //字符切割遍历 设备采集类型 针对不同值进行赋值,并进行循环插入
            for (String item : maps.get("monitorType").toString().split(",")) {
                //取当前时间  并循环前十天数据  并插入相关数据进行新增
                for (int i = 0; i < 10; i++) {  // 插入
                    EquipmentDataDO equipmentDataDO = new EquipmentDataDO();
                    //对设备数据进行基地ID   赋值  / 地块ID  赋值 / 设备分类名称赋值 赋值
                    // 将LocalDate与随机的时分秒组合成LocalDateTime
                    equipmentDataDO.setEquipmentCode(equipmentid)
                            .setBaseCode(maps.get("baseCode").toString())
                            .setPlotCode(maps.get("plotCode").toString())
                            .setCollectionType(maps.get("collectionType").toString())
                            .setMonitoringType(item)
                            .setCollectionTime(LocalDate.now().minusDays(i)
                                    .atTime(LocalTime.of(random.nextInt(24),
                                            random.nextInt(60),
                                            random.nextInt(60))))
                            .setId(IdUtil.getSnowflakeNextIdStr());
                    //监测类型数值判断并添加   对应检测数值跟单位
                    switch (item) {
                        case "土壤温度":
                        case "温度":
                            equipmentDataDO.setDataValue(String.format("%.2f", 15.0 + (32.0 - 15.0) * random.nextDouble())).setYyUnit("℃");
                            break;
                         //这里有很多就不展示了
                    }
                    //list.add(equipmentDataDO);
                    equipmentDataMapper.insert(equipmentDataDO);
                }
            }
        }
        //equipmentDataMapper.insertBatch(list);
        // 返回
        return "true";
    }

但是发现这个添加2个设备,即90条数据,竟然需要42000ms

叔叔能忍,婶婶也不能忍;

于是乎,简单参考了一下鱼皮的文章,发现一个很好用的类,可以“CompletableFuture”他的作用是可以异步的处理,类似于多线程,也可以传入线程池,这个方法这里就不做讨论了;

直接上代码,然后给你们解释:

 public String createEquipmentDataA(String... equipmentCode) {
        // 提前创建避免重复创建浪费资源
        Random random = new Random();
        String[] myArray2 = {"金龟子", "蟋蟀", "蛾"};
        //存放任务队列的集合
        List<CompletableFuture<Void>> completable = new ArrayList<>();
        //存放数据集合
        List<EquipmentDataDO> list = new LinkedList<>();
        //获取userId 以及部门ID
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        Long loginUserDeptId = SecurityFrameworkUtils.getLoginUserDeptId();
        for (String equipmentId : equipmentCode) {
            //根据设备ID  查询 基地ID  地块ID 同时查询 设备分类名称 设备监测类型
            Map<String, Object> maps = equipmentDataMapper.selectEquInfo(equipmentId);
            //字符切割遍历 设备采集类型 针对不同值进行赋值,并进行循环插入
            for (String item : maps.get("monitorType").toString().split(",")) {
                //取当前时间  并循环前十天数据  并插入相关数据进行新增
                for (int i = 0; i < 10; i++) {  // 插入
                    EquipmentDataDO equipmentDataDO = new EquipmentDataDO();
                    //设置对象属性
                    EquipmentDataDOSetParameter(equipmentDataDO,random,myArray2,equipmentId,maps,item,i,userId,loginUserDeptId);
                    list.add(equipmentDataDO);
                }
            }
        }
        //批量插入 90条数据 测试时共耗时6168ms,若使用并行流耗时11335ms
        final int batchSize =10;
        for (int i = 0; i < list.size(); i+=batchSize) {
            // 获取当前批次
            int endIndex = Math.min(i + batchSize, list.size());
            // 获取当前批次
            int finalI = i;
            // 添加任务
            completable.add(CompletableFuture.runAsync(() -> equipmentDataMapper.insertBatch(list.subList(finalI, endIndex))));
        }
        //等待所有任务完成
        CompletableFuture.allOf(completable.toArray(new CompletableFuture[0])).join();
        // 返回
        return "success, 已添加:"+list.size()+"条数据";
    }

大概流程就是,把所有要添加的数据,进行了存放list的情况,然后根据我想要的大小进行分割(为什么不直接使用insertBatch添加整个列表呢,因为我试过了添加效率比一个个还慢,需要真正52000ms左右,索性还不如使用异步的方法进行添加),所以我按照鱼皮的方案,直接使用了这个对象的异步处理(不需要返回的版本),这样在添加完后,实测共耗时:6168ms,比之前快了600%的效率;

到这里有的同学会问,这样写很麻烦,为啥不适用stream的并行流呢,嘿嘿,我替你们试过了,使用并行流,添加90条数据,共耗时:若使用并行流耗时11335ms,所有最后采用了“CompletableFuture”这个异步处理的方案;大家有时间可以都测试测试,这种方案不一定最快,最好,找到最适合自己的;

大家有时间可以学习一个这个异步处理类,说不定,真的那天就派上用场了

本文灵感来源于鱼皮:员工写了个比删库更可怕的 Bug!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值