多线程并发处理批量插入数据

前言

        通过多线程并发处理,根据值域规则过滤原始数据,将符合规则的数据插入到数据库中,并记录不符合规则的数据。

代码

//获取a表数据总量
    Integer endNumber = InfoMapper.getOriginCount();
    Integer beginNumber;
    Integer pageSize = 100000;
    //分批处理,每次处理10万条数据,id排序
    do {
         beginNumber = Math.max((endNumber - 100000), 0);
         if (0 == beginNumber) {
           pageSize = endNumber;
           }
         originList = InfoMapper.getOriginList(beginNumber, pageSize);
         endNumber = beginNumber;
         //多线程
         originLists = ListUtils.partition(originList, 20000);
         countDownLatch = new CountDownLatch(originLists.size());
         for (List<Map<String, String>> origin : originLists) {
        //过滤数据
        asyncService.filterOrigin(origin, ruleMap, countDownLatch);
        }
        countDownLatch.await();
        } while (endNumber > 0);




/**
 * 根据值域规则过滤原数据
 */
@Async("initDataThreadPoolExecutor")
public void filterOrigin(List<Map<String,String>> originMapList,Map<String,List<InitRuleVo>> ruleMap, CountDownLatch countDownLatch)
        {
        log.info("根据值域规则过滤原数据线程启动"+Thread.currentThread().getName());
        try {
            String value;
            Boolean insertFlag;
            for (Map<String,String> originMap:originMapList) {
                insertFlag =true;
            //遍历原数据的字段名
            for (Map.Entry<String,String> origin: originMap.entrySet()){
                //根据字段名获取规则数据
                if(CollectionUtils.isNotEmpty(ruleMap.get(origin.getKey()))){
                value=origin.getValue();
        //根据规则过滤数据
                    for(InitRuleVo rule : ruleMap.get(origin.getKey())){
                        insertFlag = getDataBoolean(value, insertFlag, rule);
                        }
                }
        }
        LocalCache.putValidData("initCount",(Integer)LocalCache.get("initCount")+1);
        //插入符合要求的数据
        if(insertFlag){
           originMap.keySet().retainAll(FieldList);
            InfoMapper.insertOrigin(originMap);
        }
            //记录未通过的数据id
        else{
            filterIdList.add(originMap.get("id"));
        }
            }
        }catch (Exception e) {
            e.printStackTrace();
            LocalCache.remove("initLog");
            LocalCache.remove("initCount");
            LocalCache.remove("allCount");
        } finally {
            countDownLatch.countDown();
            log.info("-----完成初始化匹配---------------" + countDownLatch.getCount() + "-------------------------");
            }
        }




/**
 *过滤条件
 */
    public Boolean getDataBoolean(String value, Boolean insertFlag, PatientInitRuleVo rule) {
        //0能否为空
        if("0".equals(rule.getRuleCode())){
            //1不可以为空
            if("1".equals(rule.getRuleContent())&& StringUtils.isBlank(value)){
                insertFlag=false;
            }
        }
        //1特殊字符
        else if("1".equals(rule.getRuleCode())){
            if(StringUtils.isBlank(value)){
                insertFlag=false;
            }else{
                String[] shieldArray=rule.getRuleContent().split(",");
                for (String shield:shieldArray) {
                    if(!shield.contains("%")&&value.equals(shield)){
                        insertFlag=false;
                    }else if(shield.startsWith("%")&&shield.endsWith("%")&&
                            value.contains(shield.replaceAll("%",""))){
                        insertFlag=false;
                    }else if(!shield.startsWith("%")&&shield.endsWith("%")&&
                            value.endsWith(shield.replaceAll("%",""))){
                        insertFlag=false;
                    }else if(shield.startsWith("%")&&!shield.endsWith("%")&&
                            value.startsWith(shield.replaceAll("%",""))){
                        insertFlag=false;
                    }
                }
            }
        }
        //2数据长度
        else if("2".equals(rule.getRuleCode())){
            if(StringUtils.isBlank(value)){
                insertFlag=false;
            }else{
                if(rule.getRuleContent().contains("-")){
                    String[] lengthArray=rule.getRuleContent().split("-");
                    if(value.length()<Integer.valueOf(lengthArray[0])||
                            value.length()>Integer.valueOf(lengthArray[1])){
                        insertFlag=false;
                    }
                }else{
                    if(value.length()!=Integer.valueOf(rule.getRuleContent())){
                        insertFlag=false;
                    }
                }
            }
        }
        //3日期格式
        else if("3".equals(rule.getRuleCode())){
            if(StringUtils.isBlank(value)){
                insertFlag=false;
            }else{
                SimpleDateFormat sdf = new SimpleDateFormat(rule.getRuleContent());
                try{
                    sdf.parse(value);
                }catch (Exception e){
                    insertFlag=false;
                }
            }
        }
        //4引用码表
        else if("4".equals(rule.getRuleCode())){
            if(StringUtils.isBlank(value)){
                insertFlag=false;
            }else{
                if(!rule.getTableContentList().contains(value)){
                    insertFlag=false;
                }
            }
        }
        //5枚举
        else if("5".equals(rule.getRuleCode())){
            if(StringUtils.isBlank(value)){
                insertFlag=false;
            }else{
                if(!rule.getRuleContent().contains(value)){
                    insertFlag=false;
                }
            }
        }
        //6正则
        else if("6".equals(rule.getRuleCode())){
            if(StringUtils.isBlank(value)){
                insertFlag=false;
            }else{
                if(!Pattern.compile(rule.getRuleContent()).matcher(value).matches()){
                    insertFlag=false;
                }
            }
        }

        return insertFlag;
    }

注释

1.通过调用 InfoMapper 中的 getOriginCount() 方法获取了原始数据的总数量,并将其存储在 endNumber 变量中。

2.beginNumber 用于跟踪分批处理的起始位置,pageSize 表示每次处理的数据量。

3.开始分批处理:

  • 计算起始位置 beginNumber 和每次处理的数据量 pageSize
  • 从数据库中获取指定范围的原始数据并存储在 originList 中。
  • 将 originList 划分成小块,每个小块包含不超过 20000 条数据,并使用多线程方式进行数据过滤。
  • 使用 CountDownLatch 来等待所有数据过滤任务完成。

4.filterOrigin 方法: 

filterOrigin 方法被标记为异步执行,它接收一个包含原始数据的列表 originMapList,一个值域规则映射 ruleMap,以及一个 CountDownLatch 用于任务控制。

filterOrigin 方法中,对 originMapList 中的数据进行遍历,针对每条数据应用一组值域规则(ruleMap 中定义的规则)。根据规则的条件,决定是否插入数据到数据库中。符合规则的数据会被保留,不符合规则的数据会被标记并记录。、最后,countDownLatch.countDown() 用于通知主线程任务完成,减少计数器值。

5.getDataBoolean 方法: 这个方法用于根据值域规则检查数据是否满足规则条件。它接收数据值、一个布尔标志 insertFlag 和一个值域规则对象,并根据规则条件更新 insertFlag 标志。规则包括是否为空、特殊字符、数据长度、日期格式、引用码表、枚举和正则表达式等条件。

6.将符合值域规则的数据插入到b表中。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值